mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-05 16:11:33 +08:00
Merge branch 'master' of github.com:storybooks/storybook into addmarkosupport
This commit is contained in:
commit
ab63faed7d
@ -2,11 +2,11 @@
|
||||
|
||||
| |[React](app/react)|[React Native](app/react-native)|[Vue](app/vue)|[Angular](app/angular)| [Polymer](app/polymer)| [Mithril](app/mithril)| [HTML](app/html)| [Marko](app/marko)|
|
||||
| ----------- |:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|
|
||||
|[a11y](addons/a11y) |+| | | | | |+| |
|
||||
|[a11y](addons/a11y) |+| |+|+|+|+|+|+|
|
||||
|[actions](addons/actions) |+|+|+|+|+|+|+|+|
|
||||
|[backgrounds](addons/backgrounds) |+| | | | |+|+| |
|
||||
|[centered](addons/centered) |+| |+| | |+|+| |
|
||||
|[events](addons/events) |+| | | | | |+| |
|
||||
|[backgrounds](addons/backgrounds) |+| |+|+|+|+|+|+|
|
||||
|[centered](addons/centered) |+| |+|+| |+|+| |
|
||||
|[events](addons/events) |+| |+|+|+|+|+|+|
|
||||
|[graphql](addons/graphql) |+| | | | | | | |
|
||||
|[info](addons/info) |+| | | | | | | |
|
||||
|[jest](addons/jest) |+| | |+| | |+| |
|
||||
@ -16,4 +16,4 @@
|
||||
|[options](addons/options) |+|+|+|+|+|+|+| |
|
||||
|[storyshots](addons/storyshots) |+|+|+|+| | |+| |
|
||||
|[storysource](addons/storysource)|+| |+|+|+|+|+|+|
|
||||
|[viewport](addons/viewport) |+| |+|+|+|+|+| |
|
||||
|[viewport](addons/viewport) |+| |+|+|+|+|+|+|
|
||||
|
75
CHANGELOG.md
75
CHANGELOG.md
@ -1,3 +1,78 @@
|
||||
# 4.0.0-alpha.7
|
||||
|
||||
2018-May-17
|
||||
|
||||
#### Breaking Changes
|
||||
|
||||
- Support webpack4 modules format [#3576](https://github.com/storybooks/storybook/pull/3576)
|
||||
|
||||
#### Features
|
||||
|
||||
- Addon-centered for Angular [#3573](https://github.com/storybooks/storybook/pull/3573)
|
||||
|
||||
#### Maintenance
|
||||
|
||||
- Generic addon decorators [#3555](https://github.com/storybooks/storybook/pull/3555)
|
||||
- Refactor transitional decorator from addon-notes [#3559](https://github.com/storybooks/storybook/pull/3559)
|
||||
|
||||
# 3.4.5
|
||||
|
||||
2018-May-17
|
||||
|
||||
#### Features
|
||||
|
||||
- Addon-info: improve prop options [#3428](https://github.com/storybooks/storybook/pull/3428)
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
- Addon-storysource: Remove nested braces in code block [#3568](https://github.com/storybooks/storybook/pull/3568)
|
||||
- Addon-info: Fix double quotes in prop table, add additional examples [#3401](https://github.com/storybooks/storybook/pull/3401)
|
||||
- Ignore any unstructured output from the package managers [#3563](https://github.com/storybooks/storybook/pull/3563)
|
||||
- Use the --use-npm flag also for version checking [#3535](https://github.com/storybooks/storybook/pull/3535)
|
||||
|
||||
# 4.0.0-alpha.6
|
||||
|
||||
2018-May-12
|
||||
|
||||
#### Breaking Changes
|
||||
|
||||
- Fix the import of external md files [#3472](https://github.com/storybooks/storybook/pull/3472)
|
||||
|
||||
#### Features
|
||||
|
||||
- Add marko support to storybooksJS [#3504](https://github.com/storybooks/storybook/pull/3504)
|
||||
- Storybook addon Jest angular suport [#3532](https://github.com/storybooks/storybook/pull/3532)
|
||||
- Storybook for HTML snippets [#3475](https://github.com/storybooks/storybook/pull/3475)
|
||||
- Feature/config custom chrome executable path [#3518](https://github.com/storybooks/storybook/pull/3518)
|
||||
- Channel-postmessage: handle events from the same window [#3519](https://github.com/storybooks/storybook/pull/3519)
|
||||
- Force re-render event [#3515](https://github.com/storybooks/storybook/pull/3515)
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
- Ignore any unstructured output from the package managers [#3563](https://github.com/storybooks/storybook/pull/3563)
|
||||
- Use the --use-npm flag also for version checking [#3535](https://github.com/storybooks/storybook/pull/3535)
|
||||
- Clean out the store if `configure` fails [#3558](https://github.com/storybooks/storybook/pull/3558)
|
||||
- Fix render order in preview [#3520](https://github.com/storybooks/storybook/pull/3520)
|
||||
|
||||
# 4.0.0-alpha.5
|
||||
|
||||
Broken release (@storybook/core-events had not been published publicly)
|
||||
|
||||
# 3.4.4
|
||||
|
||||
2018-May-12
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
- Ignore home package.json no license field [#3531](https://github.com/storybooks/storybook/pull/3531)
|
||||
- fixed Duplicate declaration h [#3409](https://github.com/storybooks/storybook/pull/3409)
|
||||
- Storyshots integrity tests options [#3418](https://github.com/storybooks/storybook/pull/3418)
|
||||
- Fix dynamic knobs [d2a289e](https://github.com/storybooks/storybook/commit/d2a289e524c51e794f5f3a34164a69ba3d5409fa)
|
||||
|
||||
#### Dependency Upgrades
|
||||
|
||||
- jest-image-snapshot version to ^2.4.1 [#3500](https://github.com/storybooks/storybook/pull/3500)
|
||||
|
||||
# 4.0.0-alpha.4
|
||||
|
||||
2018-April-27
|
||||
|
@ -1 +0,0 @@
|
||||
module.exports = require('./dist/html');
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-a11y",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "a11y addon for storybook",
|
||||
"keywords": [
|
||||
"a11y",
|
||||
@ -25,14 +25,14 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "4.0.0-alpha.4",
|
||||
"@storybook/client-logger": "4.0.0-alpha.4",
|
||||
"@storybook/components": "4.0.0-alpha.4",
|
||||
"@storybook/core-events": "4.0.0-alpha.4",
|
||||
"@storybook/addons": "4.0.0-alpha.7",
|
||||
"@storybook/client-logger": "4.0.0-alpha.7",
|
||||
"@storybook/components": "4.0.0-alpha.7",
|
||||
"@storybook/core-events": "4.0.0-alpha.7",
|
||||
"axe-core": "^3.0.2",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"glamor": "^2.20.40",
|
||||
"glamorous": "^4.12.5",
|
||||
"glamorous": "^4.13.0",
|
||||
"global": "^4.3.2",
|
||||
"prop-types": "^15.6.1"
|
||||
},
|
||||
|
@ -1,14 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import WrapStory from './components/WrapStory';
|
||||
|
||||
// Run all a11y checks inside
|
||||
class A11yManager {
|
||||
wrapStory(channel, storyFn, context, axeOptions) {
|
||||
const props = { context, storyFn, channel, axeOptions };
|
||||
|
||||
return <WrapStory {...props} />;
|
||||
}
|
||||
}
|
||||
|
||||
export default A11yManager;
|
@ -1,58 +0,0 @@
|
||||
import { Component } from 'react';
|
||||
import { findDOMNode } from 'react-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import axe from 'axe-core';
|
||||
import { logger } from '@storybook/client-logger';
|
||||
|
||||
import { CHECK_EVENT_ID, RERUN_EVENT_ID } from '../shared';
|
||||
|
||||
class WrapStory extends Component {
|
||||
static propTypes = {
|
||||
context: PropTypes.shape({}),
|
||||
storyFn: PropTypes.func,
|
||||
channel: PropTypes.shape({}),
|
||||
axeOptions: PropTypes.shape({}),
|
||||
};
|
||||
static defaultProps = {
|
||||
context: {},
|
||||
storyFn: () => {},
|
||||
channel: {},
|
||||
axeOptions: {},
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.runA11yCheck = this.runA11yCheck.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { channel } = this.props;
|
||||
channel.on(RERUN_EVENT_ID, this.runA11yCheck);
|
||||
this.runA11yCheck();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const { channel } = this.props;
|
||||
channel.removeListener(RERUN_EVENT_ID, this.runA11yCheck);
|
||||
}
|
||||
|
||||
/* eslint-disable react/no-find-dom-node */
|
||||
runA11yCheck() {
|
||||
const { channel, axeOptions } = this.props;
|
||||
const wrapper = findDOMNode(this);
|
||||
|
||||
if (wrapper !== null) {
|
||||
axe.reset();
|
||||
axe.configure(axeOptions);
|
||||
axe.run(wrapper).then(results => channel.emit(CHECK_EVENT_ID, results), logger.error);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { storyFn, context } = this.props;
|
||||
|
||||
return storyFn(context);
|
||||
}
|
||||
}
|
||||
|
||||
export default WrapStory;
|
@ -1,35 +0,0 @@
|
||||
import { document, setTimeout } from 'global';
|
||||
import axe from 'axe-core';
|
||||
import addons from '@storybook/addons';
|
||||
import Events from '@storybook/core-events';
|
||||
import { logger } from '@storybook/client-logger';
|
||||
|
||||
import { CHECK_EVENT_ID, RERUN_EVENT_ID } from './shared';
|
||||
|
||||
let axeOptions = {};
|
||||
|
||||
export const configureA11y = (options = {}) => {
|
||||
axeOptions = options;
|
||||
};
|
||||
|
||||
const runA11yCheck = () => {
|
||||
const channel = addons.getChannel();
|
||||
const wrapper = document.getElementById('root');
|
||||
|
||||
axe.reset();
|
||||
axe.configure(axeOptions);
|
||||
axe.run(wrapper).then(results => channel.emit(CHECK_EVENT_ID, results), logger.error);
|
||||
};
|
||||
|
||||
const a11ySubscription = () => {
|
||||
const channel = addons.getChannel();
|
||||
channel.on(RERUN_EVENT_ID, runA11yCheck);
|
||||
return () => channel.removeListener(RERUN_EVENT_ID, runA11yCheck);
|
||||
};
|
||||
|
||||
export const checkA11y = story => {
|
||||
addons.getChannel().emit(Events.REGISTER_SUBSCRIPTION, a11ySubscription);
|
||||
// We need to wait for rendering
|
||||
setTimeout(runA11yCheck, 0);
|
||||
return story();
|
||||
};
|
@ -1,18 +1,37 @@
|
||||
import { document } from 'global';
|
||||
import axe from 'axe-core';
|
||||
import addons from '@storybook/addons';
|
||||
import Events from '@storybook/core-events';
|
||||
import { logger } from '@storybook/client-logger';
|
||||
|
||||
import A11yManager from './A11yManager';
|
||||
import * as shared from './shared';
|
||||
import { CHECK_EVENT_ID, RERUN_EVENT_ID } from './shared';
|
||||
|
||||
const manager = new A11yManager();
|
||||
let axeOptions = {};
|
||||
|
||||
function checkA11y(storyFn, context) {
|
||||
const channel = addons.getChannel();
|
||||
return manager.wrapStory(channel, storyFn, context, axeOptions);
|
||||
}
|
||||
|
||||
function configureA11y(options = {}) {
|
||||
export const configureA11y = (options = {}) => {
|
||||
axeOptions = options;
|
||||
}
|
||||
};
|
||||
|
||||
export { checkA11y, shared, configureA11y };
|
||||
const runA11yCheck = () => {
|
||||
const channel = addons.getChannel();
|
||||
const wrapper = document.getElementById('root');
|
||||
|
||||
axe.reset();
|
||||
axe.configure(axeOptions);
|
||||
axe.run(wrapper).then(results => channel.emit(CHECK_EVENT_ID, results), logger.error);
|
||||
};
|
||||
|
||||
const a11ySubscription = () => {
|
||||
const channel = addons.getChannel();
|
||||
channel.on(Events.STORY_RENDERED, runA11yCheck);
|
||||
channel.on(RERUN_EVENT_ID, runA11yCheck);
|
||||
return () => {
|
||||
channel.removeListener(Events.STORY_RENDERED, runA11yCheck);
|
||||
channel.removeListener(RERUN_EVENT_ID, runA11yCheck);
|
||||
};
|
||||
};
|
||||
|
||||
export const checkA11y = story => {
|
||||
addons.getChannel().emit(Events.REGISTER_SUBSCRIPTION, a11ySubscription);
|
||||
return story();
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-actions",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "Action Logger addon for storybook",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
@ -20,13 +20,13 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "4.0.0-alpha.4",
|
||||
"@storybook/components": "4.0.0-alpha.4",
|
||||
"@storybook/core-events": "4.0.0-alpha.4",
|
||||
"@storybook/addons": "4.0.0-alpha.7",
|
||||
"@storybook/components": "4.0.0-alpha.7",
|
||||
"@storybook/core-events": "4.0.0-alpha.7",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"deep-equal": "^1.0.1",
|
||||
"glamor": "^2.20.40",
|
||||
"glamorous": "^4.12.5",
|
||||
"glamorous": "^4.13.0",
|
||||
"global": "^4.3.2",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"make-error": "^1.3.4",
|
||||
|
@ -57,7 +57,9 @@ const actionsSubscription = (...args) => {
|
||||
};
|
||||
|
||||
export const createDecorator = actionsFn => (...args) => story => {
|
||||
addons.getChannel().emit(Events.REGISTER_SUBSCRIPTION, actionsSubscription(actionsFn, ...args));
|
||||
if (root != null) {
|
||||
addons.getChannel().emit(Events.REGISTER_SUBSCRIPTION, actionsSubscription(actionsFn, ...args));
|
||||
}
|
||||
return story();
|
||||
};
|
||||
|
||||
|
@ -69,17 +69,3 @@ storiesOf("Button", module)
|
||||
.addDecorator(backgrounds)
|
||||
.add("with text", () => <button>Click me</button>);
|
||||
```
|
||||
|
||||
> In the case of Mithril, use these imports:
|
||||
>
|
||||
> ```js
|
||||
> import { storiesOf } from '@storybook/mithril';
|
||||
> import backgrounds from "@storybook/addon-backgrounds/mithril";
|
||||
> ```
|
||||
|
||||
> In the case of Vue, use these imports:
|
||||
>
|
||||
> ```js
|
||||
> import { storiesOf } from '@storybook/vue';
|
||||
> import backgrounds from "@storybook/addon-backgrounds/vue";
|
||||
> ```
|
||||
|
@ -1 +0,0 @@
|
||||
module.exports = require('./dist/html');
|
@ -1 +1 @@
|
||||
module.exports = require('./dist/mithril');
|
||||
module.exports = require('./dist/deprecated');
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-backgrounds",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "A storybook addon to show different backgrounds for your preview",
|
||||
"keywords": [
|
||||
"addon",
|
||||
@ -24,12 +24,12 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "4.0.0-alpha.4",
|
||||
"@storybook/core-events": "4.0.0-alpha.4",
|
||||
"@storybook/addons": "4.0.0-alpha.7",
|
||||
"@storybook/core-events": "4.0.0-alpha.7",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"global": "^4.3.2",
|
||||
"prop-types": "^15.6.1",
|
||||
"react-lifecycles-compat": "^3.0.2"
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vue": "^2.5.16"
|
||||
|
@ -93,7 +93,7 @@ export default class BackgroundPanel extends Component {
|
||||
this.setState({ backgrounds });
|
||||
const currentBackground = api.getQueryParam('background');
|
||||
|
||||
if (currentBackground) {
|
||||
if (currentBackground && backgrounds.some(bg => bg.value === currentBackground)) {
|
||||
this.updateIframe(currentBackground);
|
||||
} else if (backgrounds.filter(x => x.default).length) {
|
||||
const defaultBgs = backgrounds.filter(x => x.default);
|
||||
|
@ -1,64 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import EventEmitter from 'events';
|
||||
|
||||
import { BackgroundDecorator } from '../index';
|
||||
import Events from '../events';
|
||||
|
||||
const testStory = () => () => <p>Hello World!</p>;
|
||||
|
||||
describe('Background Decorator', () => {
|
||||
it('should exist', () => {
|
||||
const SpiedChannel = new EventEmitter();
|
||||
const backgroundDecorator = shallow(
|
||||
<BackgroundDecorator story={testStory} channel={SpiedChannel} />
|
||||
);
|
||||
expect(backgroundDecorator).toBeDefined();
|
||||
});
|
||||
|
||||
it('should send background-unset event when the component unmounts', () => {
|
||||
const SpiedChannel = new EventEmitter();
|
||||
const backgroundDecorator = shallow(
|
||||
<BackgroundDecorator story={testStory} channel={SpiedChannel} />
|
||||
);
|
||||
|
||||
const spy = jest.fn();
|
||||
SpiedChannel.on(Events.UNSET, spy);
|
||||
|
||||
backgroundDecorator.unmount();
|
||||
|
||||
expect(spy).toBeCalled();
|
||||
});
|
||||
|
||||
it('should send background-set event when the component mounts', () => {
|
||||
const SpiedChannel = new EventEmitter();
|
||||
const spy = jest.fn();
|
||||
SpiedChannel.on(Events.SET, spy);
|
||||
|
||||
shallow(<BackgroundDecorator story={testStory} channel={SpiedChannel} />);
|
||||
|
||||
expect(spy).toBeCalled();
|
||||
});
|
||||
|
||||
it('should update story on change', () => {
|
||||
const SpiedChannel = new EventEmitter();
|
||||
const nextStory = jest.fn(() => <p>I am next story!</p>);
|
||||
const backgroundDecorator = shallow(
|
||||
<BackgroundDecorator story={testStory} channel={SpiedChannel} />
|
||||
);
|
||||
|
||||
backgroundDecorator.setProps({ story: nextStory });
|
||||
expect(nextStory).toBeCalled();
|
||||
});
|
||||
|
||||
it('should not update story on other props change', () => {
|
||||
const SpiedChannel = new EventEmitter();
|
||||
const story = jest.fn(() => <p>I am the only one!</p>);
|
||||
const backgroundDecorator = shallow(
|
||||
<BackgroundDecorator story={story} channel={SpiedChannel} />
|
||||
);
|
||||
|
||||
backgroundDecorator.setProps({ randomProp: true });
|
||||
expect(story.mock.calls).toHaveLength(1);
|
||||
});
|
||||
});
|
@ -1,44 +0,0 @@
|
||||
import Vue from 'vue';
|
||||
import { vueHandler } from '../vue';
|
||||
|
||||
import Events from '../events';
|
||||
|
||||
describe('Vue handler', () => {
|
||||
it('Returns a component with a created function', () => {
|
||||
const testChannel = { emit: jest.fn() };
|
||||
const testStory = () => ({ template: '<div> testStory </div>' });
|
||||
const testContext = {
|
||||
kind: 'Foo',
|
||||
story: 'bar baz',
|
||||
};
|
||||
const testBackground = [
|
||||
{ name: 'twitter', value: '#00aced' },
|
||||
{ name: 'facebook', value: '#3b5998', default: true },
|
||||
];
|
||||
const component = vueHandler(testChannel, testBackground)(testStory, testContext);
|
||||
|
||||
expect(component).toMatchObject({
|
||||
created: expect.any(Function),
|
||||
beforeDestroy: expect.any(Function),
|
||||
render: expect.any(Function),
|
||||
});
|
||||
});
|
||||
|
||||
it('Subscribes to the channel on creation', () => {
|
||||
const testChannel = { emit: jest.fn() };
|
||||
const testStory = () => ({ render: h => h('div', ['testStory']) });
|
||||
const testContext = {
|
||||
kind: 'Foo',
|
||||
story: 'bar baz',
|
||||
};
|
||||
const testBackground = [
|
||||
{ name: 'twitter', value: '#00aced' },
|
||||
{ name: 'facebook', value: '#3b5998', default: true },
|
||||
];
|
||||
|
||||
new Vue(vueHandler(testChannel, testBackground)(testStory, testContext)).$mount();
|
||||
|
||||
expect(testChannel.emit).toHaveBeenCalledTimes(1);
|
||||
expect(testChannel.emit).toHaveBeenCalledWith(Events.SET, expect.any(Array));
|
||||
});
|
||||
});
|
8
addons/backgrounds/src/deprecated.js
Normal file
8
addons/backgrounds/src/deprecated.js
Normal file
@ -0,0 +1,8 @@
|
||||
import deprecate from 'util-deprecate';
|
||||
|
||||
import backgrounds from '.';
|
||||
|
||||
export default deprecate(
|
||||
backgrounds,
|
||||
"addon-backgrounds: framework-specific imports are deprecated, just use `import backgrounds from '@storybook/addon-backgrounds`"
|
||||
);
|
@ -1,17 +0,0 @@
|
||||
import addons from '@storybook/addons';
|
||||
import CoreEvents from '@storybook/core-events';
|
||||
|
||||
import Events from './events';
|
||||
|
||||
const subscription = () => () => addons.getChannel().emit(Events.UNSET);
|
||||
|
||||
let prevBackgrounds;
|
||||
|
||||
export default backgrounds => story => {
|
||||
if (prevBackgrounds !== backgrounds) {
|
||||
addons.getChannel().emit(Events.SET, backgrounds);
|
||||
prevBackgrounds = backgrounds;
|
||||
}
|
||||
addons.getChannel().emit(CoreEvents.REGISTER_SUBSCRIPTION, subscription);
|
||||
return story();
|
||||
};
|
@ -1,68 +1,20 @@
|
||||
import React from 'react';
|
||||
import { polyfill } from 'react-lifecycles-compat';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import addons from '@storybook/addons';
|
||||
import CoreEvents from '@storybook/core-events';
|
||||
|
||||
import Events from './events';
|
||||
|
||||
export class BackgroundDecorator extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
let prevBackgrounds;
|
||||
|
||||
const { channel } = props;
|
||||
|
||||
// A channel is explicitly passed in for testing
|
||||
if (channel) {
|
||||
this.channel = channel;
|
||||
} else {
|
||||
this.channel = addons.getChannel();
|
||||
}
|
||||
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.channel.emit(Events.SET, this.props.backgrounds);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.channel.emit(Events.UNSET);
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.state.story;
|
||||
}
|
||||
}
|
||||
|
||||
BackgroundDecorator.getDerivedStateFromProps = ({ story }, { prevStory }) => {
|
||||
if (story !== prevStory) {
|
||||
return {
|
||||
story: story(),
|
||||
prevStory: story,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
const subscription = () => () => {
|
||||
prevBackgrounds = null;
|
||||
addons.getChannel().emit(Events.UNSET);
|
||||
};
|
||||
|
||||
BackgroundDecorator.propTypes = {
|
||||
backgrounds: PropTypes.arrayOf(PropTypes.object),
|
||||
channel: PropTypes.shape({
|
||||
emit: PropTypes.func,
|
||||
on: PropTypes.func,
|
||||
removeListener: PropTypes.func,
|
||||
}),
|
||||
// eslint-disable-next-line react/no-unused-prop-types
|
||||
story: PropTypes.func.isRequired,
|
||||
export default backgrounds => story => {
|
||||
if (prevBackgrounds !== backgrounds) {
|
||||
addons.getChannel().emit(Events.SET, backgrounds);
|
||||
prevBackgrounds = backgrounds;
|
||||
}
|
||||
addons.getChannel().emit(CoreEvents.REGISTER_SUBSCRIPTION, subscription);
|
||||
return story();
|
||||
};
|
||||
|
||||
BackgroundDecorator.defaultProps = {
|
||||
backgrounds: [],
|
||||
channel: undefined,
|
||||
};
|
||||
|
||||
polyfill(BackgroundDecorator);
|
||||
|
||||
export default backgrounds => story => (
|
||||
<BackgroundDecorator story={story} backgrounds={backgrounds} />
|
||||
);
|
||||
|
@ -1,41 +0,0 @@
|
||||
/** @jsx m */
|
||||
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import m from 'mithril';
|
||||
|
||||
import addons from '@storybook/addons';
|
||||
|
||||
import Events from './events';
|
||||
|
||||
export class BackgroundDecorator {
|
||||
constructor(vnode) {
|
||||
this.props = vnode.attrs;
|
||||
|
||||
const { channel, story } = vnode.attrs;
|
||||
|
||||
// A channel is explicitly passed in for testing
|
||||
if (channel) {
|
||||
this.channel = channel;
|
||||
} else {
|
||||
this.channel = addons.getChannel();
|
||||
}
|
||||
|
||||
this.story = story();
|
||||
}
|
||||
|
||||
oncreate() {
|
||||
this.channel.emit(Events.SET, this.props.backgrounds);
|
||||
}
|
||||
|
||||
onremove() {
|
||||
this.channel.emit(Events.UNSET);
|
||||
}
|
||||
|
||||
view() {
|
||||
return m(this.story);
|
||||
}
|
||||
}
|
||||
|
||||
export default backgrounds => story => ({
|
||||
view: () => <BackgroundDecorator story={story} backgrounds={backgrounds} />,
|
||||
});
|
@ -1,30 +0,0 @@
|
||||
import addons from '@storybook/addons';
|
||||
|
||||
import Events from './events';
|
||||
|
||||
export const vueHandler = (channel, backgrounds) => (getStory, context) => ({
|
||||
data() {
|
||||
return {
|
||||
context,
|
||||
getStory,
|
||||
story: getStory(context),
|
||||
};
|
||||
},
|
||||
|
||||
render(h) {
|
||||
return h(this.story);
|
||||
},
|
||||
|
||||
created() {
|
||||
channel.emit(Events.SET, backgrounds);
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
channel.emit(Events.UNSET);
|
||||
},
|
||||
});
|
||||
|
||||
export default function makeDecorator(backgrounds) {
|
||||
const channel = addons.getChannel();
|
||||
return vueHandler(channel, backgrounds);
|
||||
}
|
@ -1 +1 @@
|
||||
module.exports = require('./dist/vue');
|
||||
module.exports = require('./dist/deprecated');
|
||||
|
@ -74,6 +74,50 @@ storiesOf('MyComponent', module)
|
||||
}));
|
||||
```
|
||||
|
||||
example for Angular with component:
|
||||
|
||||
```ts
|
||||
import { centered } from '@storybook/addon-centered/angular';
|
||||
import { storiesOf } from '@storybook/angular';
|
||||
import { AppComponent } from '../app/app.component';
|
||||
|
||||
storiesOf('Addon|Centered', module)
|
||||
.addDecorator(centered)
|
||||
.add('centered component', () => ({
|
||||
component: AppComponent,
|
||||
props: {},
|
||||
}));
|
||||
|
||||
```
|
||||
|
||||
example for Angular with template:
|
||||
|
||||
```ts
|
||||
import { centered } from '@storybook/addon-centered/angular';
|
||||
import { moduleMetadata, storiesOf } from '@storybook/angular';
|
||||
import { AppComponent } from '../app/app.component';
|
||||
|
||||
storiesOf('Addon|Centered', module)
|
||||
.addDecorator(
|
||||
moduleMetadata({
|
||||
declarations: [Button],
|
||||
})
|
||||
)
|
||||
.addDecorator(centered)
|
||||
.add('centered template', () => ({
|
||||
template: `<storybook-button-component
|
||||
[text]="text" (onClick)="onClick($event)">
|
||||
</storybook-button-component>`,
|
||||
props: {
|
||||
text: 'Hello Button',
|
||||
onClick: event => {
|
||||
console.log('some bindings work');
|
||||
console.log(event);
|
||||
},
|
||||
},
|
||||
}));
|
||||
```
|
||||
|
||||
Also, you can also add this decorator globally
|
||||
|
||||
example for React:
|
||||
|
5
addons/centered/angular.d.ts
vendored
Normal file
5
addons/centered/angular.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
import { IStory } from '@storybook/angular';
|
||||
|
||||
declare module '@storybook/addon-centered/angular' {
|
||||
export function centered(story: IStory): IStory;
|
||||
}
|
3
addons/centered/angular.js
vendored
Normal file
3
addons/centered/angular.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
import fromCentered from './dist/angular';
|
||||
|
||||
export const centered = fromCentered;
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-centered",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "Storybook decorator to center components",
|
||||
"license": "MIT",
|
||||
"author": "Muhammed Thanish <mnmtanish@gmail.com>",
|
||||
|
58
addons/centered/src/angular.js
vendored
Normal file
58
addons/centered/src/angular.js
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
import styles from './styles';
|
||||
|
||||
function getComponentSelector(component) {
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
return component.__annotations__[0].selector;
|
||||
}
|
||||
|
||||
function getTemplate(metadata) {
|
||||
let tpl = '';
|
||||
if (metadata.component) {
|
||||
const selector = getComponentSelector(metadata.component);
|
||||
tpl = `<${selector}></${selector}>`;
|
||||
}
|
||||
|
||||
if (metadata.template) {
|
||||
tpl = metadata.template;
|
||||
}
|
||||
|
||||
return `
|
||||
<div [ngStyle]="styles.style">
|
||||
<div [ngStyle]="styles.innerStyle">
|
||||
${tpl}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function getModuleMetadata(metadata) {
|
||||
const { moduleMetadata, component } = metadata;
|
||||
|
||||
if (component && !moduleMetadata) {
|
||||
return {
|
||||
declarations: [metadata.component],
|
||||
};
|
||||
}
|
||||
|
||||
if (component && moduleMetadata) {
|
||||
return {
|
||||
...moduleMetadata,
|
||||
declarations: [...moduleMetadata.declarations, metadata.component],
|
||||
};
|
||||
}
|
||||
|
||||
return moduleMetadata;
|
||||
}
|
||||
|
||||
export default function(metadataFn) {
|
||||
const metadata = metadataFn();
|
||||
|
||||
return {
|
||||
...metadata,
|
||||
template: getTemplate(metadata),
|
||||
moduleMetadata: getModuleMetadata(metadata),
|
||||
props: {
|
||||
...metadata.props,
|
||||
styles,
|
||||
},
|
||||
};
|
||||
}
|
@ -3,5 +3,4 @@ import ReactCentered from './react';
|
||||
import VueCentered from './vue';
|
||||
|
||||
const Centered = window.STORYBOOK_ENV === 'vue' ? VueCentered : ReactCentered;
|
||||
|
||||
export default Centered;
|
||||
|
@ -36,7 +36,7 @@ Then write your stories like this:
|
||||
|
||||
```js
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import WithEvents from '@storybook/addon-events';
|
||||
import withEvents from '@storybook/addon-events';
|
||||
import EventEmiter from 'event-emiter';
|
||||
|
||||
import Logger from './Logger';
|
||||
@ -47,10 +47,10 @@ const emit = emiter.emit.bind(emiter);
|
||||
|
||||
|
||||
storiesOf('WithEvents', module)
|
||||
.addDecorator(getStory => (
|
||||
<WithEvents
|
||||
emit={emit}
|
||||
events={[
|
||||
.addDecorator(
|
||||
withEvents({
|
||||
emit,
|
||||
events: [
|
||||
{
|
||||
name: EVENTS.TEST_EVENT_1,
|
||||
title: 'Test event 1',
|
||||
@ -96,10 +96,8 @@ storiesOf('WithEvents', module)
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
>
|
||||
{getStory()}
|
||||
</WithEvents>
|
||||
))
|
||||
]
|
||||
})
|
||||
)
|
||||
.add('Logger', () => <Logger emiter={emiter} />);
|
||||
```
|
||||
|
@ -1 +0,0 @@
|
||||
module.exports = require('./dist/html');
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-events",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "Add events to your Storybook stories.",
|
||||
"keywords": [
|
||||
"addon",
|
||||
@ -19,13 +19,14 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "4.0.0-alpha.4",
|
||||
"@storybook/core-events": "4.0.0-alpha.4",
|
||||
"@storybook/addons": "4.0.0-alpha.7",
|
||||
"@storybook/core-events": "4.0.0-alpha.7",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"format-json": "^1.0.3",
|
||||
"prop-types": "^15.6.1",
|
||||
"react-lifecycles-compat": "^3.0.2",
|
||||
"react-textarea-autosize": "^6.1.0"
|
||||
"react-lifecycles-compat": "^3.0.4",
|
||||
"react-textarea-autosize": "^6.1.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
|
@ -23,9 +23,6 @@ const styles = {
|
||||
|
||||
export default class Events extends Component {
|
||||
static propTypes = {
|
||||
api: PropTypes.shape({
|
||||
onStory: PropTypes.func,
|
||||
}).isRequired,
|
||||
channel: PropTypes.shape({
|
||||
on: PropTypes.func,
|
||||
emit: PropTypes.func,
|
||||
@ -39,18 +36,9 @@ export default class Events extends Component {
|
||||
|
||||
componentDidMount() {
|
||||
this.props.channel.on(EVENTS.ADD, this.onAdd);
|
||||
|
||||
this.stopListeningOnStory = this.props.api.onStory(() => {
|
||||
this.onAdd([]);
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.stopListeningOnStory) {
|
||||
this.stopListeningOnStory();
|
||||
}
|
||||
|
||||
this.unmounted = true;
|
||||
this.props.channel.removeListener(EVENTS.ADD, this.onAdd);
|
||||
}
|
||||
|
||||
|
@ -1,27 +0,0 @@
|
||||
import addons from '@storybook/addons';
|
||||
import CoreEvents from '@storybook/core-events';
|
||||
|
||||
import { EVENTS } from './constants';
|
||||
|
||||
let prevEvents;
|
||||
let currentEmit;
|
||||
|
||||
const onEmit = event => {
|
||||
currentEmit(event.name, event.payload);
|
||||
};
|
||||
|
||||
const subscription = () => {
|
||||
const channel = addons.getChannel();
|
||||
channel.on(EVENTS.EMIT, onEmit);
|
||||
return () => channel.removeListener(EVENTS.EMIT, onEmit);
|
||||
};
|
||||
|
||||
export default ({ emit, events }) => story => {
|
||||
if (prevEvents !== events) {
|
||||
addons.getChannel().emit(EVENTS.ADD, events);
|
||||
prevEvents = events;
|
||||
}
|
||||
currentEmit = emit;
|
||||
addons.getChannel().emit(CoreEvents.REGISTER_SUBSCRIPTION, subscription);
|
||||
return story();
|
||||
};
|
@ -1 +1,46 @@
|
||||
export default from './preview';
|
||||
import addons from '@storybook/addons';
|
||||
import CoreEvents from '@storybook/core-events';
|
||||
import deprecate from 'util-deprecate';
|
||||
|
||||
import { EVENTS } from './constants';
|
||||
|
||||
let prevEvents;
|
||||
let currentEmit;
|
||||
|
||||
const onEmit = event => {
|
||||
currentEmit(event.name, event.payload);
|
||||
};
|
||||
|
||||
const subscription = () => {
|
||||
const channel = addons.getChannel();
|
||||
channel.on(EVENTS.EMIT, onEmit);
|
||||
return () => {
|
||||
prevEvents = null;
|
||||
addons.getChannel().emit(EVENTS.ADD, []);
|
||||
channel.removeListener(EVENTS.EMIT, onEmit);
|
||||
};
|
||||
};
|
||||
|
||||
const addEvents = ({ emit, events }) => {
|
||||
if (prevEvents !== events) {
|
||||
addons.getChannel().emit(EVENTS.ADD, events);
|
||||
prevEvents = events;
|
||||
}
|
||||
currentEmit = emit;
|
||||
addons.getChannel().emit(CoreEvents.REGISTER_SUBSCRIPTION, subscription);
|
||||
};
|
||||
|
||||
const WithEvents = deprecate(({ children, ...options }) => {
|
||||
addEvents(options);
|
||||
return children;
|
||||
}, `<WithEvents> usage is deprecated, use .addDecorator(withEvents({emit, events})) instead`);
|
||||
|
||||
export default options => {
|
||||
if (options.children) {
|
||||
return WithEvents(options);
|
||||
}
|
||||
return story => {
|
||||
addEvents(options);
|
||||
return story();
|
||||
};
|
||||
};
|
||||
|
@ -5,10 +5,10 @@ import Panel from './components/Panel';
|
||||
import { ADDON_ID, PANEL_ID } from './constants';
|
||||
|
||||
export function register() {
|
||||
addons.register(ADDON_ID, api => {
|
||||
addons.register(ADDON_ID, () => {
|
||||
addons.addPanel(PANEL_ID, {
|
||||
title: 'Events',
|
||||
render: () => <Panel channel={addons.getChannel()} api={api} />,
|
||||
render: () => <Panel channel={addons.getChannel()} />,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -1,47 +0,0 @@
|
||||
import { Component } from 'react';
|
||||
import addons from '@storybook/addons';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { EVENTS } from './constants';
|
||||
|
||||
export default class WithEvents extends Component {
|
||||
static propTypes = {
|
||||
emit: PropTypes.func.isRequired,
|
||||
events: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
name: PropTypes.string,
|
||||
title: PropTypes.string,
|
||||
payload: PropTypes.any,
|
||||
})
|
||||
).isRequired,
|
||||
children: PropTypes.oneOfType([PropTypes.element, PropTypes.array]).isRequired,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const { events } = this.props;
|
||||
|
||||
this.channel = addons.getChannel();
|
||||
|
||||
this.channel.on(EVENTS.EMIT, this.onEmit);
|
||||
|
||||
this.channel.emit(EVENTS.ADD, events);
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
const { events } = this.props;
|
||||
|
||||
this.channel.emit(EVENTS.ADD, events);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.channel.removeListener(EVENTS.EMIT, this.onEmit);
|
||||
}
|
||||
|
||||
onEmit = event => {
|
||||
this.props.emit(event.name, event.payload);
|
||||
};
|
||||
|
||||
render() {
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-graphql",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "Storybook addon to display the GraphiQL IDE",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-info",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "A Storybook addon to show additional information for your stories.",
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
@ -13,18 +13,18 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/client-logger": "4.0.0-alpha.4",
|
||||
"@storybook/components": "4.0.0-alpha.4",
|
||||
"@storybook/client-logger": "4.0.0-alpha.7",
|
||||
"@storybook/components": "4.0.0-alpha.7",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"core-js": "2.5.6",
|
||||
"glamor": "^2.20.40",
|
||||
"glamorous": "^4.12.5",
|
||||
"glamorous": "^4.13.0",
|
||||
"global": "^4.3.2",
|
||||
"marksy": "^6.0.3",
|
||||
"nested-object-assign": "^1.0.1",
|
||||
"prop-types": "^15.6.1",
|
||||
"react-addons-create-fragment": "^15.5.3",
|
||||
"react-lifecycles-compat": "^3.0.2",
|
||||
"react-lifecycles-compat": "^3.0.4",
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -191,7 +191,6 @@ function PropVal(props) {
|
||||
} = props;
|
||||
let { val } = props;
|
||||
const { codeColors } = theme || {};
|
||||
let braceWrap = true;
|
||||
let content = null;
|
||||
const valueStyles = props.valueStyles || getValueStyles(codeColors);
|
||||
|
||||
@ -201,8 +200,10 @@ function PropVal(props) {
|
||||
if (val.length > maxPropStringLength) {
|
||||
val = `${val.slice(0, maxPropStringLength)}…`;
|
||||
}
|
||||
if (level > 1) {
|
||||
val = `'${val}'`;
|
||||
}
|
||||
content = <span style={valueStyles.string}>{val}</span>;
|
||||
braceWrap = false;
|
||||
} else if (typeof val === 'boolean') {
|
||||
content = <span style={valueStyles.bool}>{`${val}`}</span>;
|
||||
} else if (Array.isArray(val)) {
|
||||
@ -245,9 +246,7 @@ function PropVal(props) {
|
||||
);
|
||||
}
|
||||
|
||||
if (!braceWrap) return content;
|
||||
|
||||
return <span>{{content}}</span>;
|
||||
return content;
|
||||
}
|
||||
|
||||
PropVal.defaultProps = {
|
||||
|
@ -45,7 +45,7 @@ export default function Props(props) {
|
||||
<span>
|
||||
=
|
||||
<span style={propValueStyle}>
|
||||
{typeof nodeProps[name] === 'string' && '"'}
|
||||
{typeof nodeProps[name] === 'string' ? '"' : '{'}
|
||||
<PropVal
|
||||
val={nodeProps[name]}
|
||||
maxPropObjectKeys={maxPropObjectKeys}
|
||||
@ -53,7 +53,7 @@ export default function Props(props) {
|
||||
maxPropStringLength={maxPropStringLength}
|
||||
maxPropsIntoLine={maxPropsIntoLine}
|
||||
/>
|
||||
{typeof nodeProps[name] === 'string' && '"'}
|
||||
{typeof nodeProps[name] === 'string' ? '"' : '}'}
|
||||
</span>
|
||||
</span>
|
||||
)}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-jest",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "React storybook addon that show component jest report",
|
||||
"keywords": [
|
||||
"addon",
|
||||
@ -25,11 +25,11 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "4.0.0-alpha.4",
|
||||
"@storybook/components": "4.0.0-alpha.4",
|
||||
"@storybook/addons": "4.0.0-alpha.7",
|
||||
"@storybook/components": "4.0.0-alpha.7",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"glamor": "^2.20.40",
|
||||
"glamorous": "^4.12.5",
|
||||
"glamorous": "^4.13.0",
|
||||
"global": "^4.3.2",
|
||||
"prop-types": "^15.6.1"
|
||||
},
|
||||
|
@ -31,7 +31,7 @@ npm install @storybook/addon-knobs --save-dev
|
||||
Then, configure it as an addon by adding it to your `addons.js` file (located in the Storybook config directory).
|
||||
|
||||
```js
|
||||
import '@storybook/addon-knobs/register'
|
||||
import '@storybook/addon-knobs/register';
|
||||
```
|
||||
|
||||
Now, write your stories with knobs.
|
||||
@ -39,7 +39,7 @@ Now, write your stories with knobs.
|
||||
### With React
|
||||
```js
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { withKnobs, text, boolean, number } from '@storybook/addon-knobs/react';
|
||||
import { withKnobs, text, boolean, number } from '@storybook/addon-knobs';
|
||||
|
||||
const stories = storiesOf('Storybook Knobs', module);
|
||||
|
||||
@ -67,7 +67,7 @@ stories.add('as dynamic variables', () => {
|
||||
### With Angular
|
||||
```js
|
||||
import { storiesOf } from '@storybook/angular';
|
||||
import { boolean, number, text, withKnobs } from '@storybook/addon-knobs/angular';
|
||||
import { boolean, number, text, withKnobs } from '@storybook/addon-knobs';
|
||||
|
||||
import { Button } from '@storybook/angular/demo';
|
||||
|
||||
@ -98,34 +98,6 @@ 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';
|
||||
> ```
|
||||
>
|
||||
> In the case of Angular, use these imports:
|
||||
>
|
||||
> ```js
|
||||
> import { storiesOf } from '@storybook/angular';
|
||||
> import { withKnobs, text, boolean, number } from '@storybook/addon-knobs/angular';
|
||||
> ```
|
||||
>
|
||||
> In the case of Mithril, use these imports:
|
||||
>
|
||||
> ```js
|
||||
> import { storiesOf } from '@storybook/mithril';
|
||||
> import { withKnobs, text, boolean, number } from '@storybook/addon-knobs/mithril';
|
||||
> ```
|
||||
|
||||
You can see your Knobs in a Storybook panel as shown below.
|
||||
|
||||

|
||||
@ -146,7 +118,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/react';
|
||||
import { text } from '@storybook/addon-knobs';
|
||||
|
||||
const label = 'Your Name';
|
||||
const defaultValue = 'Arunoda Susiripala';
|
||||
@ -160,7 +132,7 @@ const value = text(label, defaultValue, groupId);
|
||||
Allows you to get a boolean value from the user.
|
||||
|
||||
```js
|
||||
import { boolean } from '@storybook/addon-knobs/react';
|
||||
import { boolean } from '@storybook/addon-knobs';
|
||||
|
||||
const label = 'Agree?';
|
||||
const defaultValue = false;
|
||||
@ -173,7 +145,7 @@ const value = boolean(label, defaultValue, groupId);
|
||||
Allows you to get a number from the user.
|
||||
|
||||
```js
|
||||
import { number } from '@storybook/addon-knobs/react';
|
||||
import { number } from '@storybook/addon-knobs';
|
||||
|
||||
const label = 'Age';
|
||||
const defaultValue = 78;
|
||||
@ -191,7 +163,7 @@ const value = number(label, defaultValue, {}, groupId);
|
||||
Allows you to get a number from the user using a range slider.
|
||||
|
||||
```js
|
||||
import { number } from '@storybook/addon-knobs/react';
|
||||
import { number } from '@storybook/addon-knobs';
|
||||
|
||||
const label = 'Temperature';
|
||||
const defaultValue = 73;
|
||||
@ -211,7 +183,7 @@ const value = number(label, defaultValue, options, groupId);
|
||||
Allows you to get a colour from the user.
|
||||
|
||||
```js
|
||||
import { color } from '@storybook/addon-knobs/react';
|
||||
import { color } from '@storybook/addon-knobs';
|
||||
|
||||
const label = 'Color';
|
||||
const defaultValue = '#ff00ff';
|
||||
@ -225,7 +197,7 @@ const value = color(label, defaultValue, groupId);
|
||||
Allows you to get a JSON object or array from the user.
|
||||
|
||||
```js
|
||||
import { object } from '@storybook/addon-knobs/react';
|
||||
import { object } from '@storybook/addon-knobs';
|
||||
|
||||
const label = 'Styles';
|
||||
const defaultValue = {
|
||||
@ -243,7 +215,7 @@ const value = object(label, defaultValue, groupId);
|
||||
Allows you to get an array of strings from the user.
|
||||
|
||||
```js
|
||||
import { array } from '@storybook/addon-knobs/react';
|
||||
import { array } from '@storybook/addon-knobs';
|
||||
|
||||
const label = 'Styles';
|
||||
const defaultValue = ['Red'];
|
||||
@ -256,7 +228,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/react';
|
||||
> import { array } from '@storybook/addon-knobs';
|
||||
>
|
||||
> const label = 'Styles';
|
||||
> const defaultValue = ['Red'];
|
||||
@ -274,28 +246,7 @@ const value = array(label, defaultValue, ',', groupId);
|
||||
Allows you to get a value from a select box from the user.
|
||||
|
||||
```js
|
||||
import { select } from '@storybook/addon-knobs/react';
|
||||
|
||||
const label = 'Colors';
|
||||
const options = {
|
||||
red: 'Red',
|
||||
blue: 'Blue',
|
||||
yellow: 'Yellow',
|
||||
};
|
||||
const defaultValue = 'red';
|
||||
const groupId = 'GROUP-ID1';
|
||||
|
||||
const value = select(label, options, defaultValue, groupId);
|
||||
```
|
||||
|
||||
> You can also provide options as an array like this: `['red', 'blue', 'yellow']`
|
||||
|
||||
### selectV2
|
||||
|
||||
In v4 this will replace `select`. The value from the select now uses the values from the `options` object.
|
||||
|
||||
```js
|
||||
import { selectV2 } from '@storybook/addon-knobs';
|
||||
import { select } from '@storybook/addon-knobs';
|
||||
|
||||
const label = 'Colors';
|
||||
const options = {
|
||||
@ -308,15 +259,17 @@ const options = {
|
||||
const defaultValue = 'red';
|
||||
const groupId = 'GROUP-ID1';
|
||||
|
||||
const value = selectV2(label, options, defaultValue, groupId);
|
||||
const value = select(label, options, defaultValue, groupId);
|
||||
```
|
||||
|
||||
> 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';
|
||||
import { files } from '@storybook/addon-knobs';
|
||||
|
||||
const label = 'Images';
|
||||
const defaultValue = [];
|
||||
@ -331,7 +284,7 @@ const value = files(label, accept, defaultValue);
|
||||
Allow you to get date (and time) from the user.
|
||||
|
||||
```js
|
||||
import { date } from '@storybook/addon-knobs/react';
|
||||
import { date } from '@storybook/addon-knobs';
|
||||
|
||||
const label = 'Event Date';
|
||||
const defaultValue = new Date('Jan 20 2017');
|
||||
@ -373,12 +326,12 @@ Usage:
|
||||
|
||||
```js
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { withKnobsOptions } from '@storybook/addon-knobs';
|
||||
|
||||
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.
|
||||
timestamps: true, // Doesn't emit events while user is typing.
|
||||
escapeHTML: true // Escapes strings to be safe for inserting as innerHTML. This option is true by default in storybook for Vue, Angular, and Polymer, because those frameworks allow rendering plain HTML.
|
||||
// You can still set it to false, but it's strongly unrecommendend in cases when you host your storybook on some route of your main site or web app.
|
||||
|
||||
|
2
addons/knobs/angular.js
vendored
2
addons/knobs/angular.js
vendored
@ -1 +1 @@
|
||||
module.exports = require('./dist/angular');
|
||||
module.exports = require('./dist/deprecated');
|
||||
|
@ -1 +1 @@
|
||||
module.exports = require('./dist/html');
|
||||
module.exports = require('./dist/deprecated');
|
||||
|
@ -1 +1 @@
|
||||
module.exports = require('./dist/marko');
|
||||
module.exports = require('./dist/deprecated');
|
||||
|
@ -1 +1 @@
|
||||
module.exports = require('./dist/mithril');
|
||||
module.exports = require('./dist/deprecated');
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-knobs",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "Storybook Addon Prop Editor Component",
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
@ -13,9 +13,9 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "4.0.0-alpha.4",
|
||||
"@storybook/components": "4.0.0-alpha.4",
|
||||
"@storybook/core-events": "4.0.0-alpha.4",
|
||||
"@storybook/addons": "4.0.0-alpha.7",
|
||||
"@storybook/components": "4.0.0-alpha.7",
|
||||
"@storybook/core-events": "4.0.0-alpha.7",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"deep-equal": "^1.0.1",
|
||||
"escape-html": "^1.0.3",
|
||||
@ -26,7 +26,7 @@
|
||||
"prop-types": "^15.6.1",
|
||||
"react-color": "^2.14.1",
|
||||
"react-datetime": "^2.14.0",
|
||||
"react-lifecycles-compat": "^3.0.2",
|
||||
"react-lifecycles-compat": "^3.0.4",
|
||||
"react-textarea-autosize": "^6.1.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
|
@ -1 +1 @@
|
||||
module.exports = require('./dist/polymer');
|
||||
module.exports = require('./dist/deprecated');
|
||||
|
2
addons/knobs/react.js
vendored
2
addons/knobs/react.js
vendored
@ -1 +1 @@
|
||||
module.exports = require('./dist/react');
|
||||
module.exports = require('./dist/deprecated');
|
||||
|
136
addons/knobs/src/angular/helpers.js
vendored
136
addons/knobs/src/angular/helpers.js
vendored
@ -1,136 +0,0 @@
|
||||
/* eslint no-underscore-dangle: 0 */
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import { Component, SimpleChange, ChangeDetectorRef } from '@angular/core';
|
||||
import { getParameters, getAnnotations } from './utils';
|
||||
|
||||
const getComponentMetadata = ({ component, props = {}, moduleMetadata = {} }) => {
|
||||
if (!component || typeof component !== 'function') throw new Error('No valid component provided');
|
||||
|
||||
const componentMeta = getAnnotations(component)[0] || {};
|
||||
const paramsMetadata = getParameters(component);
|
||||
|
||||
return {
|
||||
component,
|
||||
props,
|
||||
componentMeta,
|
||||
moduleMetadata,
|
||||
params: paramsMetadata,
|
||||
};
|
||||
};
|
||||
|
||||
const getAnnotatedComponent = ({ componentMeta, component, params, knobStore, channel }) => {
|
||||
const KnobWrapperComponent = function KnobWrapperComponent(cd, ...args) {
|
||||
component.call(this, ...args);
|
||||
this.cd = cd;
|
||||
this.knobChanged = this.knobChanged.bind(this);
|
||||
this.setPaneKnobs = this.setPaneKnobs.bind(this);
|
||||
};
|
||||
|
||||
KnobWrapperComponent.prototype = Object.create(component.prototype);
|
||||
KnobWrapperComponent.annotations = [new Component(componentMeta)];
|
||||
KnobWrapperComponent.parameters = [[ChangeDetectorRef], ...params];
|
||||
|
||||
KnobWrapperComponent.prototype.constructor = KnobWrapperComponent;
|
||||
KnobWrapperComponent.prototype.ngOnInit = function onInit() {
|
||||
if (component.prototype.ngOnInit) {
|
||||
component.prototype.ngOnInit.call(this);
|
||||
}
|
||||
|
||||
channel.on('addon:knobs:knobChange', this.knobChanged);
|
||||
channel.on('addon:knobs:knobClick', this.knobClicked);
|
||||
knobStore.subscribe(this.setPaneKnobs);
|
||||
this.setPaneKnobs();
|
||||
};
|
||||
|
||||
KnobWrapperComponent.prototype.ngOnDestroy = function onDestroy() {
|
||||
if (component.prototype.ngOnDestroy) {
|
||||
component.prototype.ngOnDestroy.call(this);
|
||||
}
|
||||
|
||||
channel.removeListener('addon:knobs:knobChange', this.knobChanged);
|
||||
channel.removeListener('addon:knobs:knobClick', this.knobClicked);
|
||||
knobStore.unsubscribe(this.setPaneKnobs);
|
||||
};
|
||||
|
||||
KnobWrapperComponent.prototype.ngOnChanges = function onChanges(changes) {
|
||||
if (component.prototype.ngOnChanges) {
|
||||
component.prototype.ngOnChanges.call(this, changes);
|
||||
}
|
||||
};
|
||||
|
||||
KnobWrapperComponent.prototype.setPaneKnobs = function setPaneKnobs(timestamp = +new Date()) {
|
||||
channel.emit('addon:knobs:setKnobs', {
|
||||
knobs: knobStore.getAll(),
|
||||
timestamp,
|
||||
});
|
||||
};
|
||||
|
||||
KnobWrapperComponent.prototype.knobChanged = function knobChanged(change) {
|
||||
const { name, value } = change;
|
||||
const knobOptions = knobStore.get(name);
|
||||
const oldValue = knobOptions.value;
|
||||
knobOptions.value = value;
|
||||
knobStore.markAllUnused();
|
||||
this[name] = value;
|
||||
this.cd.detectChanges();
|
||||
this.ngOnChanges({
|
||||
[name]: new SimpleChange(oldValue, value, false),
|
||||
});
|
||||
};
|
||||
|
||||
KnobWrapperComponent.prototype.knobClicked = function knobClicked(clicked) {
|
||||
const knobOptions = knobStore.get(clicked.name);
|
||||
knobOptions.callback();
|
||||
};
|
||||
|
||||
return KnobWrapperComponent;
|
||||
};
|
||||
|
||||
const createComponentFromTemplate = (template, styles) => {
|
||||
const componentClass = class DynamicComponent {};
|
||||
|
||||
return Component({
|
||||
template,
|
||||
styles,
|
||||
})(componentClass);
|
||||
};
|
||||
|
||||
const resetKnobs = (knobStore, channel) => {
|
||||
knobStore.reset();
|
||||
channel.emit('addon:knobs:setKnobs', {
|
||||
knobs: knobStore.getAll(),
|
||||
timestamp: false,
|
||||
});
|
||||
};
|
||||
|
||||
export function prepareComponent({ getStory, context, channel, knobStore }) {
|
||||
resetKnobs(knobStore, channel);
|
||||
const story = getStory(context);
|
||||
let { component } = story;
|
||||
const { template, styles } = story;
|
||||
|
||||
if (!component) {
|
||||
component = createComponentFromTemplate(template, styles);
|
||||
}
|
||||
|
||||
const { componentMeta, props, params, moduleMetadata } = getComponentMetadata({
|
||||
...story,
|
||||
component,
|
||||
});
|
||||
|
||||
if (!componentMeta && component) throw new Error('No component metadata available');
|
||||
|
||||
const AnnotatedComponent = getAnnotatedComponent({
|
||||
componentMeta,
|
||||
component,
|
||||
params,
|
||||
knobStore,
|
||||
channel,
|
||||
});
|
||||
|
||||
return {
|
||||
component: AnnotatedComponent,
|
||||
props,
|
||||
moduleMetadata,
|
||||
};
|
||||
}
|
24
addons/knobs/src/angular/index.js
vendored
24
addons/knobs/src/angular/index.js
vendored
@ -1,24 +0,0 @@
|
||||
import { prepareComponent } from './helpers';
|
||||
|
||||
import {
|
||||
knob,
|
||||
text,
|
||||
boolean,
|
||||
number,
|
||||
color,
|
||||
object,
|
||||
array,
|
||||
date,
|
||||
select,
|
||||
selectV2,
|
||||
button,
|
||||
files,
|
||||
makeDecorators,
|
||||
} from '../base';
|
||||
|
||||
export { knob, text, boolean, number, color, object, array, date, select, selectV2, button, files };
|
||||
|
||||
export const angularHandler = (channel, knobStore) => getStory => context =>
|
||||
prepareComponent({ getStory, context, channel, knobStore });
|
||||
|
||||
export const { withKnobs, withKnobsOptions } = makeDecorators(angularHandler, { escapeHTML: true });
|
38
addons/knobs/src/angular/utils.js
vendored
38
addons/knobs/src/angular/utils.js
vendored
@ -1,38 +0,0 @@
|
||||
/* globals window */
|
||||
/* eslint-disable no-param-reassign */
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import { ɵReflectionCapabilities } from '@angular/core';
|
||||
|
||||
// eslint-disable-next-line new-cap
|
||||
const reflectionCapabilities = new ɵReflectionCapabilities();
|
||||
|
||||
function getMeta(component, [name1, name2], defaultValue) {
|
||||
if (!name2) {
|
||||
name2 = name1;
|
||||
name1 = `__${name1}__`;
|
||||
}
|
||||
|
||||
if (component[name1]) {
|
||||
return component[name1];
|
||||
}
|
||||
|
||||
if (component[name2]) {
|
||||
return component[name2];
|
||||
}
|
||||
|
||||
return window.Reflect.getMetadata(name2, component) || defaultValue;
|
||||
}
|
||||
|
||||
export function getAnnotations(component) {
|
||||
return getMeta(component, ['annotations'], []);
|
||||
}
|
||||
|
||||
export function getParameters(component) {
|
||||
const params = reflectionCapabilities.parameters(component);
|
||||
|
||||
if (!params || !params[0]) {
|
||||
return getMeta(component, ['parameters'], []);
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
import deprecate from 'util-deprecate';
|
||||
import addons from '@storybook/addons';
|
||||
|
||||
import KnobManager from './KnobManager';
|
||||
|
||||
export const manager = new KnobManager();
|
||||
|
||||
export function knob(name, options) {
|
||||
return manager.knob(name, options);
|
||||
}
|
||||
|
||||
export function text(name, value, groupId) {
|
||||
return manager.knob(name, { type: 'text', value, groupId });
|
||||
}
|
||||
|
||||
export function boolean(name, value, groupId) {
|
||||
return manager.knob(name, { type: 'boolean', value, groupId });
|
||||
}
|
||||
|
||||
export function number(name, value, options = {}, groupId) {
|
||||
const rangeDefaults = {
|
||||
min: 0,
|
||||
max: 10,
|
||||
step: 1,
|
||||
};
|
||||
|
||||
const mergedOptions = options.range
|
||||
? {
|
||||
...rangeDefaults,
|
||||
...options,
|
||||
}
|
||||
: options;
|
||||
|
||||
const finalOptions = {
|
||||
...mergedOptions,
|
||||
type: 'number',
|
||||
value,
|
||||
groupId,
|
||||
};
|
||||
|
||||
return manager.knob(name, finalOptions);
|
||||
}
|
||||
|
||||
export function color(name, value, groupId) {
|
||||
return manager.knob(name, { type: 'color', value, groupId });
|
||||
}
|
||||
|
||||
export function object(name, value, groupId) {
|
||||
return manager.knob(name, { type: 'object', value, groupId });
|
||||
}
|
||||
|
||||
export const select = deprecate(
|
||||
(name, options, value, groupId) =>
|
||||
manager.knob(name, { type: 'select', options, value, groupId }),
|
||||
'in v4 keys/values of the options argument are reversed'
|
||||
);
|
||||
|
||||
export function selectV2(name, options, value, groupId) {
|
||||
return manager.knob(name, { type: 'select', selectV2: true, options, value, groupId });
|
||||
}
|
||||
|
||||
export function array(name, value, separator = ',', groupId) {
|
||||
return manager.knob(name, { type: 'array', value, separator, groupId });
|
||||
}
|
||||
|
||||
export function date(name, value = new Date(), groupId) {
|
||||
const proxyValue = value ? value.getTime() : null;
|
||||
return manager.knob(name, { type: 'date', value: proxyValue, groupId });
|
||||
}
|
||||
|
||||
export function button(name, callback, groupId) {
|
||||
return manager.knob(name, { type: 'button', callback, hideLabel: true, groupId });
|
||||
}
|
||||
|
||||
export function files(name, accept, value = []) {
|
||||
return manager.knob(name, { type: 'files', accept, value });
|
||||
}
|
||||
|
||||
export function makeDecorators(handler, defaultOptions = {}) {
|
||||
function wrapperKnobs(options) {
|
||||
const allOptions = { ...defaultOptions, ...options };
|
||||
|
||||
manager.setOptions(allOptions);
|
||||
const channel = addons.getChannel();
|
||||
manager.setChannel(channel);
|
||||
channel.emit('addon:knobs:setOptions', allOptions);
|
||||
|
||||
return handler(channel, manager.knobStore);
|
||||
}
|
||||
|
||||
return {
|
||||
withKnobs(storyFn, context) {
|
||||
return wrapperKnobs()(storyFn)(context);
|
||||
},
|
||||
withKnobsOptions(options = {}) {
|
||||
return (storyFn, context) => wrapperKnobs(options)(storyFn)(context);
|
||||
},
|
||||
};
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import debounce from 'lodash.debounce';
|
||||
|
||||
import GroupTabs from './GroupTabs';
|
||||
import PropForm from './PropForm';
|
||||
@ -81,14 +80,8 @@ export default class Panel extends React.Component {
|
||||
this.setState({ groupId: name });
|
||||
}
|
||||
|
||||
setOptions(options = { debounce: false, timestamps: false }) {
|
||||
setOptions(options = { timestamps: false }) {
|
||||
this.options = options;
|
||||
|
||||
if (options.debounce) {
|
||||
this.emitChange = debounce(this.emitChange, options.debounce.wait, {
|
||||
leading: options.debounce.leading,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setKnobs({ knobs, timestamp }) {
|
||||
|
@ -16,19 +16,7 @@ describe('Select', () => {
|
||||
};
|
||||
});
|
||||
|
||||
it('displays value', () => {
|
||||
const wrapper = shallow(<SelectType knob={knob} />);
|
||||
|
||||
const green = wrapper.find('option').first();
|
||||
expect(green.text()).toEqual('#00ff00');
|
||||
expect(green.prop('value')).toEqual('Green');
|
||||
});
|
||||
|
||||
describe('selectV2', () => {
|
||||
beforeEach(() => {
|
||||
knob.selectV2 = true;
|
||||
});
|
||||
|
||||
describe('displays value', () => {
|
||||
it('correctly maps option keys and values', () => {
|
||||
const wrapper = shallow(<SelectType knob={knob} />);
|
||||
|
||||
|
@ -18,35 +18,17 @@ const styles = {
|
||||
};
|
||||
|
||||
class SelectType extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
if (!props.knob.selectV2) {
|
||||
console.info('Select Knob V1 will be deprecated, please upgrade to V2 of Select Knob'); // eslint-disable-line no-console
|
||||
}
|
||||
}
|
||||
|
||||
renderOptionList({ options, selectV2 }) {
|
||||
renderOptionList({ options }) {
|
||||
if (Array.isArray(options)) {
|
||||
return options.map(val => this.renderOption(val, val));
|
||||
}
|
||||
return Object.keys(options).map(key => this.renderOption(key, options[key], selectV2));
|
||||
return Object.keys(options).map(key => this.renderOption(key, options[key]));
|
||||
}
|
||||
|
||||
renderOption(key, value, selectV2) {
|
||||
const opts = {
|
||||
key,
|
||||
value: key,
|
||||
};
|
||||
renderOption(key, value) {
|
||||
const opts = { key, value };
|
||||
|
||||
let display = value;
|
||||
|
||||
if (selectV2) {
|
||||
opts.value = value;
|
||||
display = key;
|
||||
}
|
||||
|
||||
return <option {...opts}>{display}</option>;
|
||||
return <option {...opts}>{key}</option>;
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -75,7 +57,6 @@ SelectType.propTypes = {
|
||||
name: PropTypes.string,
|
||||
value: PropTypes.string,
|
||||
options: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
||||
selectV2: PropTypes.bool,
|
||||
}),
|
||||
onChange: PropTypes.func,
|
||||
};
|
||||
|
31
addons/knobs/src/deprecated.js
Normal file
31
addons/knobs/src/deprecated.js
Normal file
@ -0,0 +1,31 @@
|
||||
import deprecate from 'util-deprecate';
|
||||
|
||||
import {
|
||||
knob,
|
||||
text,
|
||||
boolean,
|
||||
number,
|
||||
color,
|
||||
object,
|
||||
array,
|
||||
date,
|
||||
select,
|
||||
files,
|
||||
button,
|
||||
withKnobs as commonWithKnobs,
|
||||
withKnobsOptions as commonWithKnobsOptions,
|
||||
} from '.';
|
||||
|
||||
export { knob, text, boolean, number, color, object, array, date, select, files, button };
|
||||
|
||||
export const selectV2 = deprecate(select, 'selectV2 has been renamed to select');
|
||||
|
||||
export const withKnobs = deprecate(
|
||||
commonWithKnobs,
|
||||
"addon-knobs: framework-specific imports are deprecated, just use `import {withKnobs} from '@storybook/addon-knobs`"
|
||||
);
|
||||
|
||||
export const withKnobsOptions = deprecate(
|
||||
commonWithKnobsOptions,
|
||||
"addon-knobs: framework-specific imports are deprecated, just use `import {withKnobsOptions} from '@storybook/addon-knobs`"
|
||||
);
|
@ -1,32 +0,0 @@
|
||||
import registerKnobs from './registerKnobs';
|
||||
|
||||
import {
|
||||
knob,
|
||||
text,
|
||||
boolean,
|
||||
number,
|
||||
color,
|
||||
object,
|
||||
array,
|
||||
date,
|
||||
select,
|
||||
files,
|
||||
manager,
|
||||
makeDecorators,
|
||||
} 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 });
|
||||
}
|
||||
|
||||
function prepareComponent({ getStory, context }) {
|
||||
registerKnobs();
|
||||
|
||||
return getStory(context);
|
||||
}
|
||||
|
||||
export const htmlHandler = () => getStory => context => prepareComponent({ getStory, context });
|
||||
|
||||
export const { withKnobs, withKnobsOptions } = makeDecorators(htmlHandler, { escapeHTML: true });
|
@ -1,56 +1,86 @@
|
||||
import { window } from 'global';
|
||||
import deprecate from 'util-deprecate';
|
||||
import addons from '@storybook/addons';
|
||||
|
||||
import { vueHandler } from './vue';
|
||||
import { reactHandler } from './react';
|
||||
import { manager, registerKnobs } from './registerKnobs';
|
||||
|
||||
import {
|
||||
array,
|
||||
boolean,
|
||||
button,
|
||||
files,
|
||||
color,
|
||||
date,
|
||||
knob,
|
||||
manager,
|
||||
number,
|
||||
object,
|
||||
select,
|
||||
selectV2,
|
||||
text,
|
||||
} from './base';
|
||||
export function knob(name, options) {
|
||||
return manager.knob(name, options);
|
||||
}
|
||||
|
||||
export { knob, text, boolean, number, color, object, array, date, button, select, selectV2, files };
|
||||
export function text(name, value, groupId) {
|
||||
return manager.knob(name, { type: 'text', value, groupId });
|
||||
}
|
||||
|
||||
deprecate(() => {},
|
||||
'Using @storybook/addon-knobs directly is discouraged, please use @storybook/addon-knobs/{{framework}}');
|
||||
export function boolean(name, value, groupId) {
|
||||
return manager.knob(name, { type: 'boolean', value, groupId });
|
||||
}
|
||||
|
||||
// generic higher-order component decorator for all platforms - usage is discouraged
|
||||
// This file Should be removed with 4.0 release
|
||||
function wrapperKnobs(options) {
|
||||
export function number(name, value, options = {}, groupId) {
|
||||
const rangeDefaults = {
|
||||
min: 0,
|
||||
max: 10,
|
||||
step: 1,
|
||||
};
|
||||
|
||||
const mergedOptions = options.range
|
||||
? {
|
||||
...rangeDefaults,
|
||||
...options,
|
||||
}
|
||||
: options;
|
||||
|
||||
const finalOptions = {
|
||||
...mergedOptions,
|
||||
type: 'number',
|
||||
value,
|
||||
groupId,
|
||||
};
|
||||
|
||||
return manager.knob(name, finalOptions);
|
||||
}
|
||||
|
||||
export function color(name, value, groupId) {
|
||||
return manager.knob(name, { type: 'color', value, groupId });
|
||||
}
|
||||
|
||||
export function object(name, value, groupId) {
|
||||
return manager.knob(name, { type: 'object', value, groupId });
|
||||
}
|
||||
|
||||
export function select(name, options, value, groupId) {
|
||||
return manager.knob(name, { type: 'select', selectV2: true, options, value, groupId });
|
||||
}
|
||||
|
||||
export function array(name, value, separator = ',', groupId) {
|
||||
return manager.knob(name, { type: 'array', value, separator, groupId });
|
||||
}
|
||||
|
||||
export function date(name, value = new Date(), groupId) {
|
||||
const proxyValue = value ? value.getTime() : null;
|
||||
return manager.knob(name, { type: 'date', value: proxyValue, groupId });
|
||||
}
|
||||
|
||||
export function button(name, callback, groupId) {
|
||||
return manager.knob(name, { type: 'button', callback, hideLabel: true, groupId });
|
||||
}
|
||||
|
||||
export function files(name, accept, value = []) {
|
||||
return manager.knob(name, { type: 'files', accept, value });
|
||||
}
|
||||
|
||||
const defaultOptions = {
|
||||
escapeHTML: true,
|
||||
};
|
||||
|
||||
export const withKnobsOptions = (options = {}) => storyFn => {
|
||||
const allOptions = { ...defaultOptions, ...options };
|
||||
|
||||
manager.setOptions(allOptions);
|
||||
const channel = addons.getChannel();
|
||||
manager.setChannel(channel);
|
||||
channel.emit('addon:knobs:setOptions', allOptions);
|
||||
|
||||
if (options) channel.emit('addon:knobs:setOptions', options);
|
||||
registerKnobs();
|
||||
return storyFn();
|
||||
};
|
||||
|
||||
switch (window.STORYBOOK_ENV) {
|
||||
case 'vue': {
|
||||
return vueHandler(channel, manager.knobStore);
|
||||
}
|
||||
case 'react': {
|
||||
return reactHandler(channel, manager.knobStore);
|
||||
}
|
||||
default: {
|
||||
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);
|
||||
}
|
||||
export const withKnobs = withKnobsOptions();
|
||||
|
@ -1,70 +0,0 @@
|
||||
class {
|
||||
|
||||
onCreate(input) {
|
||||
this.props = input.props;
|
||||
this.knobChanged = this.knobChanged.bind(this);
|
||||
this.knobClicked = this.knobClicked.bind(this);
|
||||
this.resetKnobs = this.resetKnobs.bind(this);
|
||||
this.setPaneKnobs = this.setPaneKnobs.bind(this);
|
||||
}
|
||||
|
||||
onMount() {
|
||||
// Watch for changes in knob editor.
|
||||
this.props.channel.on('addon:knobs:knobChange', this.knobChanged);
|
||||
// Watch for clicks in knob editor.
|
||||
this.props.channel.on('addon:knobs:knobClick', this.knobClicked);
|
||||
// Watch for the reset event and reset knobs.
|
||||
this.props.channel.on('addon:knobs:reset', this.resetKnobs);
|
||||
// Watch for any change in the knobStore and set the panel again for those changes.
|
||||
this.props.knobStore.subscribe(this.setPaneKnobs);
|
||||
// Set knobs in the panel for the first time.
|
||||
this.setPaneKnobs();
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
this.props.channel.removeListener('addon:knobs:knobChange', this.knobChanged);
|
||||
this.props.channel.removeListener('addon:knobs:knobClick', this.knobClicked);
|
||||
this.props.channel.removeListener('addon:knobs:reset', this.resetKnobs);
|
||||
this.props.knobStore.unsubscribe(this.setPaneKnobs);
|
||||
}
|
||||
|
||||
setPaneKnobs(timestamp = +new Date()) {
|
||||
const { channel, knobStore } = this.props;
|
||||
channel.emit('addon:knobs:setKnobs', { knobs: knobStore.getAll(), timestamp });
|
||||
}
|
||||
|
||||
knobChanged(change) {
|
||||
const { name, value } = change;
|
||||
const { knobStore, storyFn, context } = this.props;
|
||||
|
||||
// Update the related knob and it's value.
|
||||
var knobOptions = knobStore.get(name);
|
||||
knobOptions.value = value;
|
||||
knobStore.markAllUnused();
|
||||
|
||||
this.renderElement(storyFn(context));
|
||||
}
|
||||
|
||||
knobClicked(clicked) {
|
||||
let knobOptions = this.props.knobStore.get(clicked.name);
|
||||
knobOptions.callback();
|
||||
}
|
||||
|
||||
resetKnobs() {
|
||||
const { knobStore, storyFn, context } = this.props;
|
||||
knobStore.reset();
|
||||
this.renderElement(storyFn(context));
|
||||
this.setPaneKnobs(false);
|
||||
}
|
||||
|
||||
renderElement(storyContent) {
|
||||
var WrapperElm = document.getElementById('Wrapper');
|
||||
if(this.currLoadedComponent) {
|
||||
this.currLoadedComponent.destroy();
|
||||
this.currLoadedComponent = null;
|
||||
}
|
||||
this.currLoadedComponent = storyContent.appendTo(WrapperElm).getComponent();
|
||||
}
|
||||
}
|
||||
|
||||
<div id="Wrapper"></div>
|
@ -1,43 +0,0 @@
|
||||
import addons from '@storybook/addons';
|
||||
import WrapStory from './WrapStory.marko';
|
||||
|
||||
import {
|
||||
knob,
|
||||
text,
|
||||
boolean,
|
||||
number,
|
||||
color,
|
||||
object,
|
||||
array,
|
||||
date,
|
||||
select,
|
||||
selectV2,
|
||||
button,
|
||||
manager,
|
||||
} from '../base';
|
||||
|
||||
export { knob, text, boolean, number, color, object, array, date, select, selectV2, button };
|
||||
|
||||
export const markoHandler = (channel, knobStore) => getStory => context => {
|
||||
const initialContent = getStory(context);
|
||||
const props = { context, storyFn: getStory, channel, knobStore, initialContent };
|
||||
|
||||
return WrapStory.renderSync({ props });
|
||||
};
|
||||
|
||||
function wrapperKnobs(options) {
|
||||
const channel = addons.getChannel();
|
||||
manager.setChannel(channel);
|
||||
|
||||
if (options) channel.emit('addon:knobs:setOptions', options);
|
||||
|
||||
return markoHandler(channel, manager.knobStore);
|
||||
}
|
||||
|
||||
export function withKnobs(storyFn, context) {
|
||||
return wrapperKnobs()(storyFn)(context);
|
||||
}
|
||||
|
||||
export function withKnobsOptions(options = {}) {
|
||||
return (storyFn, context) => wrapperKnobs(options)(storyFn)(context);
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import m from 'mithril';
|
||||
|
||||
export default class WrapStory {
|
||||
constructor(vnode) {
|
||||
this.knobChanged = this.knobChanged.bind(this);
|
||||
this.knobClicked = this.knobClicked.bind(this);
|
||||
this.resetKnobs = this.resetKnobs.bind(this);
|
||||
this.setPaneKnobs = this.setPaneKnobs.bind(this);
|
||||
this.props = vnode.attrs;
|
||||
this.storyContent = vnode.attrs.initialContent;
|
||||
}
|
||||
|
||||
oncreate() {
|
||||
// Watch for changes in knob editor.
|
||||
this.props.channel.on('addon:knobs:knobChange', this.knobChanged);
|
||||
// Watch for clicks in knob editor.
|
||||
this.props.channel.on('addon:knobs:knobClick', this.knobClicked);
|
||||
// Watch for the reset event and reset knobs.
|
||||
this.props.channel.on('addon:knobs:reset', this.resetKnobs);
|
||||
// Watch for any change in the knobStore and set the panel again for those
|
||||
// changes.
|
||||
this.props.knobStore.subscribe(this.setPaneKnobs);
|
||||
// Set knobs in the panel for the first time.
|
||||
this.setPaneKnobs();
|
||||
}
|
||||
|
||||
onremove() {
|
||||
this.props.channel.removeListener('addon:knobs:knobChange', this.knobChanged);
|
||||
this.props.channel.removeListener('addon:knobs:knobClick', this.knobClicked);
|
||||
this.props.channel.removeListener('addon:knobs:reset', this.resetKnobs);
|
||||
this.props.knobStore.unsubscribe(this.setPaneKnobs);
|
||||
}
|
||||
|
||||
setPaneKnobs(timestamp = +new Date()) {
|
||||
const { channel, knobStore } = this.props;
|
||||
channel.emit('addon:knobs:setKnobs', { knobs: knobStore.getAll(), timestamp });
|
||||
}
|
||||
|
||||
knobChanged(change) {
|
||||
const { name, value } = change;
|
||||
const { knobStore, storyFn, context } = this.props;
|
||||
// Update the related knob and it's value.
|
||||
const knobOptions = knobStore.get(name);
|
||||
|
||||
knobOptions.value = value;
|
||||
knobStore.markAllUnused();
|
||||
this.storyContent = storyFn(context);
|
||||
m.redraw();
|
||||
}
|
||||
|
||||
knobClicked(clicked) {
|
||||
const knobOptions = this.props.knobStore.get(clicked.name);
|
||||
knobOptions.callback();
|
||||
}
|
||||
|
||||
resetKnobs() {
|
||||
const { knobStore, storyFn, context } = this.props;
|
||||
knobStore.reset();
|
||||
this.storyContent = storyFn(context);
|
||||
m.redraw();
|
||||
this.setPaneKnobs(false);
|
||||
}
|
||||
|
||||
view() {
|
||||
return m(this.storyContent);
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
/** @jsx m */
|
||||
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import m from 'mithril';
|
||||
|
||||
import WrapStory from './WrapStory';
|
||||
|
||||
import {
|
||||
knob,
|
||||
text,
|
||||
boolean,
|
||||
number,
|
||||
color,
|
||||
object,
|
||||
array,
|
||||
date,
|
||||
select,
|
||||
selectV2,
|
||||
button,
|
||||
makeDecorators,
|
||||
} from '../base';
|
||||
|
||||
export { knob, text, boolean, number, color, object, array, date, select, selectV2, button };
|
||||
|
||||
export const mithrilHandler = (channel, knobStore) => getStory => context => {
|
||||
const initialContent = getStory(context);
|
||||
const props = { context, storyFn: getStory, channel, knobStore, initialContent };
|
||||
return {
|
||||
view: () => <WrapStory {...props} />,
|
||||
};
|
||||
};
|
||||
|
||||
export const { withKnobs, withKnobsOptions } = makeDecorators(mithrilHandler);
|
@ -1,94 +0,0 @@
|
||||
<dom-module id="wrap-story">
|
||||
<script>
|
||||
import { html, render, TemplateResult } from 'lit-html';
|
||||
|
||||
class WrapStory extends HTMLElement {
|
||||
static get is() {
|
||||
return 'wrap-story';
|
||||
}
|
||||
|
||||
constructor(component, channel, context, storyFn, knobStore) {
|
||||
super();
|
||||
|
||||
this.attachShadow({ mode: 'open' });
|
||||
this.shadowRoot.innerHTML = '<div id="wrapper"></div>';
|
||||
|
||||
this.channel = channel;
|
||||
this.context = context;
|
||||
this.storyFn = storyFn;
|
||||
this.knobStore = knobStore;
|
||||
|
||||
this.knobChanged = this.knobChanged.bind(this);
|
||||
this.knobClicked = this.knobClicked.bind(this);
|
||||
this.resetKnobs = this.resetKnobs.bind(this);
|
||||
this.setPaneKnobs = this.setPaneKnobs.bind(this);
|
||||
|
||||
this.connectChannel(this.channel);
|
||||
this.knobStore.subscribe(this.setPaneKnobs);
|
||||
this.render(component);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.disconnectChannel(this.channel);
|
||||
this.knobStore.unsubscribe(this.setPaneKnobs);
|
||||
}
|
||||
|
||||
connectChannel(channel) {
|
||||
channel.on('addon:knobs:knobChange', this.knobChanged);
|
||||
channel.on('addon:knobs:knobClick', this.knobClicked);
|
||||
channel.on('addon:knobs:reset', this.resetKnobs);
|
||||
}
|
||||
|
||||
disconnectChannel(channel) {
|
||||
channel.removeListener('addon:knobs:knobChange', this.knobChanged);
|
||||
channel.removeListener('addon:knobs:knobClick', this.knobClicked);
|
||||
channel.removeListener('addon:knobs:reset', this.resetKnobs);
|
||||
}
|
||||
|
||||
knobChanged(change) {
|
||||
const { name, value } = change;
|
||||
const { knobStore, storyFn, context } = this;
|
||||
// Update the related knob and it's value.
|
||||
const knobOptions = knobStore.get(name);
|
||||
|
||||
knobOptions.value = value;
|
||||
knobStore.markAllUnused();
|
||||
this.render(storyFn(context));
|
||||
}
|
||||
|
||||
knobClicked(clicked) {
|
||||
const knobOptions = this.knobStore.get(clicked.name);
|
||||
knobOptions.callback();
|
||||
}
|
||||
|
||||
resetKnobs() {
|
||||
const { knobStore, storyFn, context } = this;
|
||||
knobStore.reset();
|
||||
this.render(storyFn(context));
|
||||
this.setPaneKnobs(this.channel, this.knobStore, false);
|
||||
}
|
||||
|
||||
setPaneKnobs(timestamp = +new Date()) {
|
||||
const { channel, knobStore } = this;
|
||||
channel.emit('addon:knobs:setKnobs', { knobs: knobStore.getAll(), timestamp });
|
||||
}
|
||||
|
||||
render(component) {
|
||||
const wrapper = this.shadowRoot.querySelector('div#wrapper');
|
||||
if (typeof component === 'string') {
|
||||
wrapper.innerHTML = component;
|
||||
} else if (component instanceof TemplateResult) {
|
||||
//`render` stores the TemplateInstance in the Node and tries to update based on that.
|
||||
//Since we reuse `rootElement` for all stories, remove the stored instance first.
|
||||
render(html``, wrapper);
|
||||
render(component, wrapper);
|
||||
} else {
|
||||
wrapper.innerHTML = '';
|
||||
wrapper.appendChild(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(WrapStory.is, WrapStory);
|
||||
</script>
|
||||
</dom-module>
|
@ -1,33 +0,0 @@
|
||||
import window from 'global';
|
||||
import './WrapStory.html';
|
||||
|
||||
import {
|
||||
knob,
|
||||
text,
|
||||
boolean,
|
||||
number,
|
||||
color,
|
||||
object,
|
||||
array,
|
||||
date,
|
||||
select,
|
||||
files,
|
||||
manager,
|
||||
makeDecorators,
|
||||
} 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 });
|
||||
}
|
||||
|
||||
function prepareComponent({ getStory, context, channel, knobStore }) {
|
||||
const WrapStory = window.customElements.get('wrap-story');
|
||||
return new WrapStory(getStory(context), channel, context, getStory, knobStore);
|
||||
}
|
||||
|
||||
export const polymerHandler = (channel, knobStore) => getStory => context =>
|
||||
prepareComponent({ getStory, context, channel, knobStore });
|
||||
|
||||
export const { withKnobs, withKnobsOptions } = makeDecorators(polymerHandler, { escapeHTML: true });
|
@ -1,109 +0,0 @@
|
||||
/* eslint no-underscore-dangle: 0 */
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { polyfill } from 'react-lifecycles-compat';
|
||||
|
||||
class WrapStory extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.knobChanged = this.knobChanged.bind(this);
|
||||
this.knobClicked = this.knobClicked.bind(this);
|
||||
this.resetKnobs = this.resetKnobs.bind(this);
|
||||
this.setPaneKnobs = this.setPaneKnobs.bind(this);
|
||||
this._knobsAreReset = false;
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// Watch for changes in knob editor.
|
||||
this.props.channel.on('addon:knobs:knobChange', this.knobChanged);
|
||||
// Watch for clicks in knob editor.
|
||||
this.props.channel.on('addon:knobs:knobClick', this.knobClicked);
|
||||
// Watch for the reset event and reset knobs.
|
||||
this.props.channel.on('addon:knobs:reset', this.resetKnobs);
|
||||
// Watch for any change in the knobStore and set the panel again for those
|
||||
// changes.
|
||||
this.props.knobStore.subscribe(this.setPaneKnobs);
|
||||
// Set knobs in the panel for the first time.
|
||||
this.setPaneKnobs();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.channel.removeListener('addon:knobs:knobChange', this.knobChanged);
|
||||
this.props.channel.removeListener('addon:knobs:knobClick', this.knobClicked);
|
||||
this.props.channel.removeListener('addon:knobs:reset', this.resetKnobs);
|
||||
this.props.knobStore.unsubscribe(this.setPaneKnobs);
|
||||
}
|
||||
|
||||
setPaneKnobs(timestamp = +new Date()) {
|
||||
const { channel, knobStore } = this.props;
|
||||
channel.emit('addon:knobs:setKnobs', { knobs: knobStore.getAll(), timestamp });
|
||||
}
|
||||
|
||||
knobChanged(change) {
|
||||
const { name, value } = change;
|
||||
const { knobStore, storyFn, context } = this.props;
|
||||
// Update the related knob and it's value.
|
||||
const knobOptions = knobStore.get(name);
|
||||
|
||||
knobOptions.value = value;
|
||||
knobStore.markAllUnused();
|
||||
this.setState({ storyContent: storyFn(context) });
|
||||
}
|
||||
|
||||
knobClicked(clicked) {
|
||||
const knobOptions = this.props.knobStore.get(clicked.name);
|
||||
knobOptions.callback();
|
||||
}
|
||||
|
||||
resetKnobs() {
|
||||
const { knobStore, storyFn, context } = this.props;
|
||||
knobStore.reset();
|
||||
this.setState({ storyContent: storyFn(context) });
|
||||
this.setPaneKnobs(false);
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.state.storyContent;
|
||||
}
|
||||
}
|
||||
|
||||
WrapStory.getDerivedStateFromProps = ({ initialContent }, { prevContent }) => {
|
||||
if (initialContent !== prevContent) {
|
||||
return {
|
||||
storyContent: initialContent,
|
||||
prevContent: initialContent,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
WrapStory.defaultProps = {
|
||||
context: {},
|
||||
initialContent: {},
|
||||
storyFn: context => context,
|
||||
};
|
||||
|
||||
WrapStory.propTypes = {
|
||||
context: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
storyFn: PropTypes.func,
|
||||
channel: PropTypes.shape({
|
||||
on: PropTypes.func,
|
||||
removeListener: PropTypes.func,
|
||||
}).isRequired,
|
||||
knobStore: PropTypes.shape({
|
||||
channel: PropTypes.func,
|
||||
get: PropTypes.func,
|
||||
getAll: PropTypes.func,
|
||||
markAllUnused: PropTypes.func,
|
||||
reset: PropTypes.func,
|
||||
subscribe: PropTypes.func,
|
||||
unsubscribe: PropTypes.func,
|
||||
}).isRequired,
|
||||
initialContent: PropTypes.node, // eslint-disable-line react/no-unused-prop-types
|
||||
};
|
||||
|
||||
polyfill(WrapStory);
|
||||
|
||||
export default WrapStory;
|
@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import WrapStory from './WrapStory';
|
||||
|
||||
import {
|
||||
knob,
|
||||
text,
|
||||
boolean,
|
||||
number,
|
||||
color,
|
||||
object,
|
||||
array,
|
||||
date,
|
||||
select,
|
||||
selectV2,
|
||||
button,
|
||||
files,
|
||||
makeDecorators,
|
||||
} from '../base';
|
||||
|
||||
export { knob, text, boolean, number, color, object, array, date, select, selectV2, button, files };
|
||||
|
||||
export const reactHandler = (channel, knobStore) => getStory => context => {
|
||||
const initialContent = getStory(context);
|
||||
const props = { context, storyFn: getStory, channel, knobStore, initialContent };
|
||||
return <WrapStory {...props} />;
|
||||
};
|
||||
|
||||
export const { withKnobs, withKnobsOptions } = makeDecorators(reactHandler);
|
@ -1,27 +0,0 @@
|
||||
import React from 'react';
|
||||
import { reactHandler } from './index';
|
||||
import { shallow } from 'enzyme'; // eslint-disable-line
|
||||
import KnobStore from '../KnobStore';
|
||||
|
||||
describe('React Handler', () => {
|
||||
describe('wrapStory', () => {
|
||||
it('should contain the story and add correct props', () => {
|
||||
const testChannel = { emit: jest.fn(), on: jest.fn() };
|
||||
const testStory = () => <div id="test-story">Test Content</div>;
|
||||
const testContext = {
|
||||
kind: 'Foo',
|
||||
story: 'bar baz',
|
||||
};
|
||||
|
||||
const testStore = new KnobStore();
|
||||
|
||||
const wrappedStory = reactHandler(testChannel, testStore)(testStory)(testContext);
|
||||
const wrapper = shallow(wrappedStory);
|
||||
expect(wrapper.find('#test-story')).toHaveLength(1);
|
||||
|
||||
const storyWrapperProps = wrappedStory.props;
|
||||
expect(storyWrapperProps.channel).toEqual(testChannel);
|
||||
expect(storyWrapperProps.context).toEqual(testContext);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,7 +1,8 @@
|
||||
import addons from '@storybook/addons';
|
||||
import Events from '@storybook/core-events';
|
||||
import { manager } from '../base';
|
||||
import KnobManager from './KnobManager';
|
||||
|
||||
export const manager = new KnobManager();
|
||||
const { knobStore } = manager;
|
||||
|
||||
function forceReRender() {
|
||||
@ -35,8 +36,7 @@ function resetKnobs() {
|
||||
|
||||
forceReRender();
|
||||
|
||||
const channel = addons.getChannel();
|
||||
setPaneKnobs(channel, knobStore, false);
|
||||
setPaneKnobs(false);
|
||||
}
|
||||
|
||||
function disconnectCallbacks() {
|
||||
@ -57,8 +57,6 @@ function connectCallbacks() {
|
||||
return disconnectCallbacks;
|
||||
}
|
||||
|
||||
function registerKnobs() {
|
||||
export function registerKnobs() {
|
||||
addons.getChannel().emit(Events.REGISTER_SUBSCRIPTION, connectCallbacks);
|
||||
}
|
||||
|
||||
export default registerKnobs;
|
@ -1,75 +0,0 @@
|
||||
import {
|
||||
knob,
|
||||
text,
|
||||
boolean,
|
||||
number,
|
||||
color,
|
||||
object,
|
||||
array,
|
||||
date,
|
||||
select,
|
||||
selectV2,
|
||||
button,
|
||||
files,
|
||||
makeDecorators,
|
||||
} from '../base';
|
||||
|
||||
export { knob, text, boolean, number, color, object, array, date, select, selectV2, button, files };
|
||||
|
||||
export const vueHandler = (channel, knobStore) => getStory => context => ({
|
||||
data() {
|
||||
return {
|
||||
context,
|
||||
getStory,
|
||||
story: getStory(context),
|
||||
};
|
||||
},
|
||||
|
||||
render(h) {
|
||||
return h(this.story);
|
||||
},
|
||||
|
||||
methods: {
|
||||
onKnobChange(change) {
|
||||
const { name, value } = change;
|
||||
// Update the related knob and it's value.
|
||||
const knobOptions = knobStore.get(name);
|
||||
|
||||
knobOptions.value = value;
|
||||
this.story = this.getStory(this.context);
|
||||
this.$forceUpdate();
|
||||
},
|
||||
|
||||
onKnobClick(clicked) {
|
||||
const knobOptions = knobStore.get(clicked.name);
|
||||
knobOptions.callback();
|
||||
},
|
||||
|
||||
onKnobReset() {
|
||||
knobStore.reset();
|
||||
this.setPaneKnobs(false);
|
||||
this.story = this.getStory(this.context);
|
||||
this.$forceUpdate();
|
||||
},
|
||||
|
||||
setPaneKnobs(timestamp = +new Date()) {
|
||||
channel.emit('addon:knobs:setKnobs', { knobs: knobStore.getAll(), timestamp });
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
channel.on('addon:knobs:reset', this.onKnobReset);
|
||||
channel.on('addon:knobs:knobChange', this.onKnobChange);
|
||||
channel.on('addon:knobs:knobClick', this.onKnobClick);
|
||||
knobStore.subscribe(this.setPaneKnobs);
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
channel.removeListener('addon:knobs:reset', this.onKnobReset);
|
||||
channel.removeListener('addon:knobs:knobChange', this.onKnobChange);
|
||||
channel.removeListener('addon:knobs:knobClick', this.onKnobClick);
|
||||
knobStore.unsubscribe(this.setPaneKnobs);
|
||||
},
|
||||
});
|
||||
|
||||
export const { withKnobs, withKnobsOptions } = makeDecorators(vueHandler, { escapeHTML: true });
|
@ -1,40 +0,0 @@
|
||||
import Vue from 'vue';
|
||||
import { vueHandler } from './index';
|
||||
import KnobStore from '../KnobStore';
|
||||
|
||||
describe('Vue handler', () => {
|
||||
it('Returns a component with a created function', () => {
|
||||
const testChannel = { emit: jest.fn(), on: jest.fn() };
|
||||
const testStory = () => ({ template: '<div> testStory </div>' });
|
||||
const testContext = {
|
||||
kind: 'Foo',
|
||||
story: 'bar baz',
|
||||
};
|
||||
|
||||
const testStore = new KnobStore();
|
||||
const component = vueHandler(testChannel, testStore)(testStory)(testContext);
|
||||
|
||||
expect(component).toMatchObject({
|
||||
created: expect.any(Function),
|
||||
beforeDestroy: expect.any(Function),
|
||||
render: expect.any(Function),
|
||||
});
|
||||
});
|
||||
|
||||
it('Subscribes to the channel on creation', () => {
|
||||
const testChannel = { emit: () => {}, on: jest.fn() };
|
||||
const testStory = () => ({ render: h => h('div', ['testStory']) });
|
||||
const testContext = {
|
||||
kind: 'Foo',
|
||||
story: 'bar baz',
|
||||
};
|
||||
|
||||
const testStore = new KnobStore();
|
||||
new Vue(vueHandler(testChannel, testStore)(testStory)(testContext)).$mount();
|
||||
|
||||
expect(testChannel.on).toHaveBeenCalledTimes(3);
|
||||
expect(testChannel.on).toHaveBeenCalledWith('addon:knobs:reset', expect.any(Function));
|
||||
expect(testChannel.on).toHaveBeenCalledWith('addon:knobs:knobChange', expect.any(Function));
|
||||
expect(testChannel.on).toHaveBeenCalledWith('addon:knobs:knobClick', expect.any(Function));
|
||||
});
|
||||
});
|
@ -1 +1 @@
|
||||
module.exports = require('./dist/vue');
|
||||
module.exports = require('./dist/deprecated');
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-links",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "Story Links addon for storybook",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
@ -20,9 +20,9 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "4.0.0-alpha.4",
|
||||
"@storybook/components": "4.0.0-alpha.4",
|
||||
"@storybook/core-events": "4.0.0-alpha.4",
|
||||
"@storybook/addons": "4.0.0-alpha.7",
|
||||
"@storybook/components": "4.0.0-alpha.7",
|
||||
"@storybook/core-events": "4.0.0-alpha.7",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"global": "^4.3.2",
|
||||
"prop-types": "^15.6.1"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-notes",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "Write notes for your Storybook stories.",
|
||||
"keywords": [
|
||||
"addon",
|
||||
@ -18,7 +18,7 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "4.0.0-alpha.4",
|
||||
"@storybook/addons": "4.0.0-alpha.7",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"marked": "^0.3.19",
|
||||
"prop-types": "^15.6.1",
|
||||
|
@ -1,7 +1,7 @@
|
||||
import addons from '@storybook/addons';
|
||||
import { withNotes } from '..';
|
||||
|
||||
jest.mock('@storybook/addons');
|
||||
addons.getChannel = jest.fn();
|
||||
|
||||
describe('Storybook Addon Notes', () => {
|
||||
it('should inject text from `notes` parameter', () => {
|
||||
@ -16,6 +16,18 @@ describe('Storybook Addon Notes', () => {
|
||||
expect(getStory).toHaveBeenCalledWith(context);
|
||||
});
|
||||
|
||||
it('should NOT inject text if no `notes` parameter', () => {
|
||||
const channel = { emit: jest.fn() };
|
||||
addons.getChannel.mockReturnValue(channel);
|
||||
|
||||
const getStory = jest.fn();
|
||||
const context = {};
|
||||
|
||||
withNotes(getStory, context);
|
||||
expect(channel.emit).not.toHaveBeenCalled();
|
||||
expect(getStory).toHaveBeenCalledWith(context);
|
||||
});
|
||||
|
||||
it('should inject markdown from `notes.markdown` parameter', () => {
|
||||
const channel = { emit: jest.fn() };
|
||||
addons.getChannel.mockReturnValue(channel);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import addons from '@storybook/addons';
|
||||
import addons, { makeDecorator } from '@storybook/addons';
|
||||
import marked from 'marked';
|
||||
|
||||
function renderMarkdown(text, options) {
|
||||
@ -6,43 +6,30 @@ function renderMarkdown(text, options) {
|
||||
return marked(text);
|
||||
}
|
||||
|
||||
const decorator = options => {
|
||||
const channel = addons.getChannel();
|
||||
return (getStory, context) => {
|
||||
const {
|
||||
parameters: { notes },
|
||||
} = context;
|
||||
const storyOptions = notes || options;
|
||||
export const withNotes = makeDecorator({
|
||||
name: 'withNotes',
|
||||
parameterName: 'notes',
|
||||
skipIfNoParametersOrOptions: true,
|
||||
wrapper: (getStory, context, { options, parameters }) => {
|
||||
const channel = addons.getChannel();
|
||||
|
||||
if (storyOptions) {
|
||||
const { text, markdown, markdownOptions } =
|
||||
typeof storyOptions === 'string' ? { text: storyOptions } : storyOptions;
|
||||
const storyOptions = parameters || options;
|
||||
|
||||
if (!text && !markdown) {
|
||||
throw new Error('You must set of one of `text` or `markdown` on the `notes` parameter');
|
||||
}
|
||||
const { text, markdown, markdownOptions } =
|
||||
typeof storyOptions === 'string' ? { text: storyOptions } : storyOptions;
|
||||
|
||||
channel.emit('storybook/notes/add_notes', text || renderMarkdown(markdown, markdownOptions));
|
||||
if (!text && !markdown) {
|
||||
throw new Error('You must set of one of `text` or `markdown` on the `notes` parameter');
|
||||
}
|
||||
|
||||
return getStory(context);
|
||||
};
|
||||
};
|
||||
channel.emit('storybook/notes/add_notes', text || renderMarkdown(markdown, markdownOptions));
|
||||
|
||||
const hoc = options => story => context => decorator(options)(story, context);
|
||||
return getStory(context);
|
||||
},
|
||||
});
|
||||
|
||||
export const withMarkdownNotes = (text, options) =>
|
||||
hoc({
|
||||
withNotes({
|
||||
markdown: text,
|
||||
markdownOptions: options,
|
||||
});
|
||||
|
||||
export const withNotes = (...args) => {
|
||||
// Used without options as .addDecorator(withNotes)
|
||||
if (typeof args[0] === 'function') {
|
||||
return decorator()(...args);
|
||||
}
|
||||
|
||||
// Input are options, ala .add('name', withNotes('note')(() => <Story/>))
|
||||
return hoc(args[0]);
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-options",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "Options addon for storybook",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
@ -19,7 +19,7 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "4.0.0-alpha.4",
|
||||
"@storybook/addons": "4.0.0-alpha.7",
|
||||
"babel-runtime": "^6.26.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-storyshots",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "StoryShots is a Jest Snapshot Testing Addon for Storybook.",
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
@ -16,22 +16,22 @@
|
||||
"storybook": "start-storybook -p 6006"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "4.0.0-alpha.4",
|
||||
"@storybook/core": "4.0.0-alpha.4",
|
||||
"@storybook/node-logger": "4.0.0-alpha.4",
|
||||
"@storybook/addons": "4.0.0-alpha.7",
|
||||
"@storybook/core": "4.0.0-alpha.7",
|
||||
"@storybook/node-logger": "4.0.0-alpha.7",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"glob": "^7.1.2",
|
||||
"global": "^4.3.2",
|
||||
"jest-image-snapshot": "^2.4.1",
|
||||
"jest-specific-snapshot": "^0.5.0",
|
||||
"puppeteer": "^1.3.0",
|
||||
"puppeteer": "^1.4.0",
|
||||
"read-pkg-up": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@storybook/addon-actions": "4.0.0-alpha.4",
|
||||
"@storybook/addon-links": "4.0.0-alpha.4",
|
||||
"@storybook/addons": "4.0.0-alpha.4",
|
||||
"@storybook/react": "4.0.0-alpha.4",
|
||||
"@storybook/addon-actions": "4.0.0-alpha.7",
|
||||
"@storybook/addon-links": "4.0.0-alpha.7",
|
||||
"@storybook/addons": "4.0.0-alpha.7",
|
||||
"@storybook/react": "4.0.0-alpha.7",
|
||||
"enzyme-to-json": "^3.3.3",
|
||||
"react": "^16.3.2"
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-storysource",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "Stories addon for storybook",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
@ -20,8 +20,8 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "4.0.0-alpha.4",
|
||||
"@storybook/components": "4.0.0-alpha.4",
|
||||
"@storybook/addons": "4.0.0-alpha.7",
|
||||
"@storybook/components": "4.0.0-alpha.7",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"estraverse": "^4.2.0",
|
||||
"loader-utils": "^1.1.0",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/addon-viewport",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "Storybook addon to change the viewport size to mobile",
|
||||
"keywords": [
|
||||
"storybook"
|
||||
@ -11,12 +11,14 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "4.0.0-alpha.4",
|
||||
"@storybook/components": "4.0.0-alpha.4",
|
||||
"@storybook/addons": "4.0.0-alpha.7",
|
||||
"@storybook/components": "4.0.0-alpha.7",
|
||||
"@storybook/core-events": "4.0.0-alpha.7",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"global": "^4.3.2",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"prop-types": "^15.6.1"
|
||||
"prop-types": "^15.6.1",
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
|
@ -1,52 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import addons from '@storybook/addons';
|
||||
import {
|
||||
SET_STORY_DEFAULT_VIEWPORT_EVENT_ID,
|
||||
VIEWPORT_CHANGED_EVENT_ID,
|
||||
DEFAULT_VIEWPORT,
|
||||
} from '../../shared';
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
export default class Viewport extends React.Component {
|
||||
static propTypes = {
|
||||
name: PropTypes.string,
|
||||
children: PropTypes.node.isRequired,
|
||||
onViewportChange: PropTypes.func,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
name: DEFAULT_VIEWPORT,
|
||||
onViewportChange: noop,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.channel = addons.getChannel();
|
||||
const { onViewportChange } = props;
|
||||
|
||||
if (typeof this.props.onViewportChange === 'function') {
|
||||
this.onViewportChange = onViewportChange;
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.onViewportChange) {
|
||||
this.channel.on(VIEWPORT_CHANGED_EVENT_ID, this.onViewportChange);
|
||||
}
|
||||
|
||||
this.channel.emit(SET_STORY_DEFAULT_VIEWPORT_EVENT_ID, this.props.name);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.onViewportChange) {
|
||||
this.channel.removeListener(VIEWPORT_CHANGED_EVENT_ID, this.onViewportChange);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
import React from 'react';
|
||||
import addons from '@storybook/addons';
|
||||
import { shallow } from 'enzyme';
|
||||
import { EventEmitter } from 'events';
|
||||
import Viewport from '../Viewport';
|
||||
import { VIEWPORT_CHANGED_EVENT_ID, INITIAL_VIEWPORTS } from '../../../shared';
|
||||
|
||||
jest.mock('@storybook/addons');
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
describe('Viewport', () => {
|
||||
const channel = {
|
||||
emit: jest.fn(),
|
||||
on: jest.fn(),
|
||||
removeListener: jest.fn(),
|
||||
};
|
||||
|
||||
addons.getChannel.mockReturnValue(channel);
|
||||
|
||||
const props = {
|
||||
name: 'iphone6',
|
||||
children: '1337',
|
||||
};
|
||||
|
||||
let subject;
|
||||
|
||||
beforeEach(() => {
|
||||
subject = shallow(<Viewport {...props} />);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
channel.emit.mockReset();
|
||||
channel.on.mockReset();
|
||||
channel.removeListener.mockReset();
|
||||
});
|
||||
|
||||
describe('componentDidMount', () => {
|
||||
it('publishes `set` event with `iphone6`', () => {
|
||||
expect(channel.emit).toHaveBeenCalledTimes(1);
|
||||
expect(channel.emit).toHaveBeenCalledWith(
|
||||
'addon:viewport:setStoryDefaultViewport',
|
||||
'iphone6'
|
||||
);
|
||||
});
|
||||
|
||||
it('should listen to viewport changes', () => {
|
||||
channel.on.mockReset();
|
||||
subject = shallow(<Viewport {...props} onViewportChange={noop} />);
|
||||
|
||||
expect(channel.on).toHaveBeenCalledTimes(1);
|
||||
expect(channel.on).toHaveBeenCalledWith('addon:viewport:viewportChanged', noop);
|
||||
});
|
||||
});
|
||||
|
||||
describe('componentWillUnmount', () => {
|
||||
it('removes viewport changes listener', () => {
|
||||
subject = shallow(<Viewport {...props} onViewportChange={noop} />);
|
||||
subject.unmount();
|
||||
|
||||
expect(channel.removeListener).toHaveBeenCalledTimes(1);
|
||||
expect(channel.removeListener).toHaveBeenCalledWith('addon:viewport:viewportChanged', noop);
|
||||
});
|
||||
});
|
||||
|
||||
describe('onViewportChange', () => {
|
||||
const emitter = new EventEmitter();
|
||||
const propsWithCallback = {
|
||||
name: 'unknown',
|
||||
children: 'do not exist',
|
||||
onViewportChange: jest.fn(),
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
addons.getChannel.mockReturnValue(emitter);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
subject = shallow(<Viewport {...propsWithCallback} />);
|
||||
});
|
||||
|
||||
it('calls onViewportChange with the newly selected viewport', () => {
|
||||
emitter.emit(VIEWPORT_CHANGED_EVENT_ID, {
|
||||
viewport: INITIAL_VIEWPORTS.iphone5,
|
||||
});
|
||||
|
||||
expect(propsWithCallback.onViewportChange).toHaveBeenCalled();
|
||||
expect(propsWithCallback.onViewportChange).toHaveBeenCalledWith({
|
||||
viewport: INITIAL_VIEWPORTS.iphone5,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -2,8 +2,7 @@ import addons from '@storybook/addons';
|
||||
import { CONFIGURE_VIEWPORT_EVENT_ID } from '../shared';
|
||||
|
||||
export { INITIAL_VIEWPORTS, DEFAULT_VIEWPORT } from '../shared';
|
||||
export { default as withViewport } from './withViewport';
|
||||
export { default as Viewport } from './components/Viewport';
|
||||
export { default as withViewport, Viewport } from './withViewport';
|
||||
|
||||
export function configureViewport(configs = {}) {
|
||||
const channel = addons.getChannel();
|
||||
|
@ -1,20 +1,46 @@
|
||||
import React from 'react';
|
||||
import addons from '@storybook/addons';
|
||||
import CoreEvents from '@storybook/core-events';
|
||||
import deprecate from 'util-deprecate';
|
||||
|
||||
import Viewport from './components/Viewport';
|
||||
import {
|
||||
SET_STORY_DEFAULT_VIEWPORT_EVENT_ID,
|
||||
VIEWPORT_CHANGED_EVENT_ID,
|
||||
DEFAULT_VIEWPORT,
|
||||
} from '../shared';
|
||||
|
||||
function noop() {}
|
||||
let handler = noop;
|
||||
|
||||
const subscription = () => {
|
||||
const channel = addons.getChannel();
|
||||
channel.on(VIEWPORT_CHANGED_EVENT_ID, handler);
|
||||
return () => channel.removeListener(VIEWPORT_CHANGED_EVENT_ID, handler);
|
||||
};
|
||||
|
||||
const setViewport = options => {
|
||||
const channel = addons.getChannel();
|
||||
handler = options.onViewportChange || noop;
|
||||
if (options.onViewportChange) {
|
||||
channel.emit(CoreEvents.REGISTER_SUBSCRIPTION, subscription);
|
||||
}
|
||||
channel.emit(SET_STORY_DEFAULT_VIEWPORT_EVENT_ID, options.name || DEFAULT_VIEWPORT);
|
||||
};
|
||||
|
||||
export default function withViewport(nameOrOptions) {
|
||||
const options = typeof nameOrOptions === 'string' ? { name: nameOrOptions } : nameOrOptions;
|
||||
|
||||
const decorator = getStory => context => (
|
||||
<Viewport context={context} {...options}>
|
||||
{getStory()}
|
||||
</Viewport>
|
||||
);
|
||||
return (story, context) => {
|
||||
const decorated = () => {
|
||||
setViewport(options);
|
||||
return story();
|
||||
};
|
||||
|
||||
return (getStory, context) => {
|
||||
if (typeof context === 'undefined') {
|
||||
return decorator(getStory);
|
||||
}
|
||||
return decorator(getStory)(context);
|
||||
// Absent context means a direct call, withViewport(viewport)(storyFn)
|
||||
return context ? decorated() : decorated;
|
||||
};
|
||||
}
|
||||
|
||||
export const Viewport = deprecate(({ children, ...options }) => {
|
||||
setViewport(options);
|
||||
return children;
|
||||
}, `<Viewport> usage is deprecated, use .addDecorator(withViewport(viewport)) instead`);
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/angular",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "Storybook for Angular: Develop Angular Components in isolation with Hot Reloading.",
|
||||
"homepage": "https://github.com/storybooks/storybook/tree/master/apps/angular",
|
||||
"bugs": {
|
||||
@ -22,14 +22,14 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/core": "4.0.0-alpha.4",
|
||||
"@storybook/node-logger": "4.0.0-alpha.4",
|
||||
"@storybook/core": "4.0.0-alpha.7",
|
||||
"@storybook/node-logger": "4.0.0-alpha.7",
|
||||
"@storybook/react-dev-utils": "^5.0.0",
|
||||
"airbnb-js-shims": "^1.4.1",
|
||||
"angular2-template-loader": "^0.6.2",
|
||||
"babel-loader": "^7.1.4",
|
||||
"babel-plugin-macros": "^2.2.0",
|
||||
"babel-preset-env": "^1.6.0",
|
||||
"babel-plugin-macros": "^2.2.1",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"babel-preset-stage-0": "^6.24.1",
|
||||
"babel-runtime": "^6.23.0",
|
||||
"case-sensitive-paths-webpack-plugin": "^2.1.2",
|
||||
@ -39,9 +39,9 @@
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"raw-loader": "^0.5.1",
|
||||
"sass-loader": "^7.0.1",
|
||||
"ts-loader": "^4.2.0",
|
||||
"webpack": "^4.8.0",
|
||||
"webpack-hot-middleware": "^2.22.1",
|
||||
"ts-loader": "^4.3.0",
|
||||
"webpack": "^4.8.3",
|
||||
"webpack-hot-middleware": "^2.22.2",
|
||||
"zone.js": "^0.8.26"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/html",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "Storybook for HTML: View HTML snippets in isolation with Hot Reloading.",
|
||||
"homepage": "https://github.com/storybooks/storybook/tree/master/apps/html",
|
||||
"bugs": {
|
||||
@ -21,15 +21,15 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/core": "4.0.0-alpha.4",
|
||||
"@storybook/core": "4.0.0-alpha.7",
|
||||
"@storybook/react-dev-utils": "^5.0.0",
|
||||
"airbnb-js-shims": "^1.4.1",
|
||||
"babel-loader": "^7.1.4",
|
||||
"babel-plugin-macros": "^2.2.0",
|
||||
"babel-plugin-macros": "^2.2.1",
|
||||
"babel-plugin-transform-regenerator": "^6.26.0",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-preset-env": "^1.6.0",
|
||||
"babel-preset-minify": "^0.4.1",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"babel-preset-minify": "^0.4.2",
|
||||
"babel-preset-stage-0": "^6.24.1",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"case-sensitive-paths-webpack-plugin": "^2.1.2",
|
||||
@ -40,8 +40,8 @@
|
||||
"html-loader": "^0.5.5",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"raw-loader": "^0.5.1",
|
||||
"webpack": "^4.8.0",
|
||||
"webpack-hot-middleware": "^2.22.1"
|
||||
"webpack": "^4.8.3",
|
||||
"webpack-hot-middleware": "^2.22.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"babel-core": "^6.26.0 || ^7.0.0-0",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/marko",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "Storybook for Marko: Develop Marko Component in isolation with Hot Reloading.",
|
||||
"homepage": "https://github.com/storybooks/storybook/tree/master/app/marko",
|
||||
"bugs": {
|
||||
@ -22,19 +22,19 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addons": "4.0.0-alpha.4",
|
||||
"@storybook/channel-postmessage": "4.0.0-alpha.4",
|
||||
"@storybook/client-logger": "4.0.0-alpha.4",
|
||||
"@storybook/core": "4.0.0-alpha.4",
|
||||
"@storybook/node-logger": "4.0.0-alpha.4",
|
||||
"@storybook/ui": "4.0.0-alpha.4",
|
||||
"@storybook/addons": "4.0.0-alpha.7",
|
||||
"@storybook/channel-postmessage": "4.0.0-alpha.7",
|
||||
"@storybook/client-logger": "4.0.0-alpha.7",
|
||||
"@storybook/core": "4.0.0-alpha.7",
|
||||
"@storybook/node-logger": "4.0.0-alpha.7",
|
||||
"@storybook/ui": "4.0.0-alpha.7",
|
||||
"airbnb-js-shims": "^1.4.1",
|
||||
"babel-loader": "^7.1.4",
|
||||
"babel-plugin-macros": "^2.2.0",
|
||||
"babel-plugin-macros": "^2.2.1",
|
||||
"babel-plugin-transform-regenerator": "^6.26.0",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-preset-env": "^1.6.1",
|
||||
"babel-preset-minify": "^0.3.0",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"babel-preset-minify": "^0.4.2",
|
||||
"babel-preset-stage-0": "^6.24.1",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"case-sensitive-paths-webpack-plugin": "^2.1.2",
|
||||
@ -42,15 +42,15 @@
|
||||
"core-js": "^2.5.4",
|
||||
"dotenv-webpack": "^1.5.5",
|
||||
"glamor": "^2.20.40",
|
||||
"glamorous": "^4.12.1",
|
||||
"glamorous": "^4.13.0",
|
||||
"global": "^4.3.2",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"marko-loader": "^1.3.3",
|
||||
"raw-loader": "^0.5.1",
|
||||
"lodash.flattendeep": "^4.4.0",
|
||||
"marko-loader": "^1.3.3",
|
||||
"prop-types": "^15.6.1",
|
||||
"webpack": "^4.5.0",
|
||||
"webpack-hot-middleware": "^2.21.2"
|
||||
"raw-loader": "^0.5.1",
|
||||
"webpack": "^4.8.3",
|
||||
"webpack-hot-middleware": "^2.22.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"babel-core": "^6.26.0 || ^7.0.0-0",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/mithril",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "Storybook for Mithril: Develop Mithril Component in isolation.",
|
||||
"homepage": "https://github.com/storybooks/storybook/tree/master/app/mithril",
|
||||
"bugs": {
|
||||
@ -22,15 +22,15 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/core": "4.0.0-alpha.4",
|
||||
"@storybook/core": "4.0.0-alpha.7",
|
||||
"@storybook/react-dev-utils": "^5.0.0",
|
||||
"airbnb-js-shims": "^1.4.1",
|
||||
"babel-loader": "^7.1.4",
|
||||
"babel-plugin-macros": "^2.2.0",
|
||||
"babel-plugin-macros": "^2.2.1",
|
||||
"babel-plugin-transform-regenerator": "^6.26.0",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-preset-env": "^1.6.1",
|
||||
"babel-preset-minify": "^0.4.1",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"babel-preset-minify": "^0.4.2",
|
||||
"babel-preset-stage-0": "^6.24.1",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"case-sensitive-paths-webpack-plugin": "^2.1.2",
|
||||
@ -40,8 +40,8 @@
|
||||
"global": "^4.3.2",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"raw-loader": "^0.5.1",
|
||||
"webpack": "^4.8.0",
|
||||
"webpack-hot-middleware": "^2.22.1"
|
||||
"webpack": "^4.8.3",
|
||||
"webpack-hot-middleware": "^2.22.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mithril": "^1.1.6"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/polymer",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "Storybook for Polymer: Develop Polymer components in isolation with Hot Reloading.",
|
||||
"homepage": "https://github.com/storybooks/storybook/tree/master/apps/polymer",
|
||||
"bugs": {
|
||||
@ -21,16 +21,16 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/core": "4.0.0-alpha.4",
|
||||
"@storybook/core": "4.0.0-alpha.7",
|
||||
"@storybook/react-dev-utils": "^5.0.0",
|
||||
"@webcomponents/webcomponentsjs": "^1.2.0",
|
||||
"airbnb-js-shims": "^1.4.1",
|
||||
"babel-loader": "^7.1.4",
|
||||
"babel-plugin-macros": "^2.2.0",
|
||||
"babel-plugin-macros": "^2.2.1",
|
||||
"babel-plugin-transform-regenerator": "^6.26.0",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"babel-preset-env": "^1.6.0",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"babel-preset-minify": "^0.4.1",
|
||||
"babel-preset-stage-0": "^6.24.1",
|
||||
"babel-runtime": "^6.26.0",
|
||||
@ -41,8 +41,8 @@
|
||||
"global": "^4.3.2",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"raw-loader": "^0.5.1",
|
||||
"webpack": "^4.8.0",
|
||||
"webpack-hot-middleware": "^2.22.1"
|
||||
"webpack": "^4.8.3",
|
||||
"webpack-hot-middleware": "^2.22.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"lit-html": "^0.10.0",
|
||||
|
@ -4,7 +4,14 @@ import { html, render, TemplateResult } from 'lit-html';
|
||||
|
||||
const rootElement = document.getElementById('root');
|
||||
|
||||
export default function renderMain({ story, selectedKind, selectedStory, showMain, showError }) {
|
||||
export default function renderMain({
|
||||
story,
|
||||
selectedKind,
|
||||
selectedStory,
|
||||
showMain,
|
||||
showError,
|
||||
forceRender,
|
||||
}) {
|
||||
const component = story();
|
||||
|
||||
if (!component) {
|
||||
@ -24,7 +31,10 @@ export default function renderMain({ story, selectedKind, selectedStory, showMai
|
||||
} else if (component instanceof TemplateResult) {
|
||||
// `render` stores the TemplateInstance in the Node and tries to update based on that.
|
||||
// Since we reuse `rootElement` for all stories, remove the stored instance first.
|
||||
render(html``, rootElement);
|
||||
// But forceRender means that it's the same story, so we want too keep the state in that case.
|
||||
if (!forceRender) {
|
||||
render(html``, rootElement);
|
||||
}
|
||||
render(component, rootElement);
|
||||
} else {
|
||||
rootElement.innerHTML = '';
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/react-native",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "A better way to develop React Native Components for your app",
|
||||
"keywords": [
|
||||
"react",
|
||||
@ -25,25 +25,25 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addon-actions": "4.0.0-alpha.4",
|
||||
"@storybook/addon-links": "4.0.0-alpha.4",
|
||||
"@storybook/addons": "4.0.0-alpha.4",
|
||||
"@storybook/channel-websocket": "4.0.0-alpha.4",
|
||||
"@storybook/core": "4.0.0-alpha.4",
|
||||
"@storybook/core-events": "4.0.0-alpha.4",
|
||||
"@storybook/addon-actions": "4.0.0-alpha.7",
|
||||
"@storybook/addon-links": "4.0.0-alpha.7",
|
||||
"@storybook/addons": "4.0.0-alpha.7",
|
||||
"@storybook/channel-websocket": "4.0.0-alpha.7",
|
||||
"@storybook/core": "4.0.0-alpha.7",
|
||||
"@storybook/core-events": "4.0.0-alpha.7",
|
||||
"@storybook/react-dev-utils": "^5.0.0",
|
||||
"@storybook/ui": "4.0.0-alpha.4",
|
||||
"@storybook/ui": "4.0.0-alpha.7",
|
||||
"babel-loader": "^7.1.4",
|
||||
"babel-plugin-macros": "^2.2.0",
|
||||
"babel-plugin-macros": "^2.2.1",
|
||||
"babel-plugin-syntax-async-functions": "^6.13.0",
|
||||
"babel-plugin-syntax-trailing-function-commas": "^6.22.0",
|
||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||
"babel-plugin-transform-object-rest-spread": "^6.23.0",
|
||||
"babel-plugin-transform-regenerator": "^6.26.0",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-preset-env": "^1.6.1",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"babel-preset-flow": "^6.23.0",
|
||||
"babel-preset-minify": "^0.4.1",
|
||||
"babel-preset-minify": "^0.4.2",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
"babel-register": "^6.26.0",
|
||||
"babel-runtime": "^6.26.0",
|
||||
@ -58,14 +58,14 @@
|
||||
"prop-types": "^15.6.1",
|
||||
"raw-loader": "^0.5.1",
|
||||
"react-native-compat": "^1.0.0",
|
||||
"react-native-iphone-x-helper": "^1.0.2",
|
||||
"shelljs": "^0.8.1",
|
||||
"react-native-iphone-x-helper": "^1.0.3",
|
||||
"shelljs": "^0.8.2",
|
||||
"url-parse": "^1.4.0",
|
||||
"util-deprecate": "^1.0.2",
|
||||
"uuid": "^3.2.1",
|
||||
"webpack": "^4.8.0",
|
||||
"webpack": "^4.8.3",
|
||||
"webpack-dev-middleware": "^3.1.3",
|
||||
"webpack-hot-middleware": "^2.22.1",
|
||||
"webpack-hot-middleware": "^2.22.2",
|
||||
"ws": "^5.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
3
app/react-native/src/manager/provider.js
vendored
3
app/react-native/src/manager/provider.js
vendored
@ -56,6 +56,9 @@ export default class ReactProvider extends Provider {
|
||||
this.selection = { kind, story };
|
||||
this.channel.emit(Events.SET_CURRENT_STORY, this.selection);
|
||||
});
|
||||
this.channel.on(Events.SELECT_STORY, ({ kind, story }) => {
|
||||
api.selectStory(kind, story);
|
||||
});
|
||||
this.channel.on(Events.SET_STORIES, data => {
|
||||
api.setStories(data.stories);
|
||||
});
|
||||
|
@ -10,12 +10,15 @@ export default class StoryView extends Component {
|
||||
this.state = { storyFn: null, selection: {} };
|
||||
|
||||
this.storyHandler = this.selectStory.bind(this);
|
||||
this.forceRender = this.forceUpdate.bind(this);
|
||||
|
||||
this.props.events.on(Events.SELECT_STORY, this.storyHandler);
|
||||
this.props.events.on(Events.FORCE_RE_RENDER, this.forceRender);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.events.removeListener(Events.SELECT_STORY, this.storyHandler);
|
||||
this.props.events.removeListener(Events.FORCE_RE_RENDER, this.forceRender);
|
||||
}
|
||||
|
||||
selectStory(storyFn, selection) {
|
||||
|
13
app/react-native/src/preview/index.js
vendored
13
app/react-native/src/preview/index.js
vendored
@ -69,7 +69,8 @@ export default class Preview {
|
||||
}
|
||||
channel.on(Events.GET_STORIES, () => this._sendSetStories());
|
||||
channel.on(Events.SET_CURRENT_STORY, d => this._selectStory(d));
|
||||
this._events.on(Events.SET_CURRENT_STORY, d => this._selectStory(d));
|
||||
channel.on(Events.FORCE_RE_RENDER, () => this._forceRender());
|
||||
this._events.on(Events.SET_CURRENT_STORY, d => this._selectStory(d, true));
|
||||
this._sendSetStories();
|
||||
this._sendGetCurrentStory();
|
||||
|
||||
@ -93,9 +94,17 @@ export default class Preview {
|
||||
channel.emit(Events.GET_CURRENT_STORY);
|
||||
}
|
||||
|
||||
_selectStory(selection) {
|
||||
_selectStory(selection, fromPreview) {
|
||||
const { kind, story } = selection;
|
||||
const storyFn = this._stories.getStoryWithContext(kind, story);
|
||||
if (fromPreview) {
|
||||
const channel = addons.getChannel();
|
||||
channel.emit(Events.SELECT_STORY, selection);
|
||||
}
|
||||
this._events.emit(Events.SELECT_STORY, storyFn, selection);
|
||||
}
|
||||
|
||||
_forceRender() {
|
||||
this._events.emit(Events.FORCE_RE_RENDER);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/react",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "Storybook for React: Develop React Component in isolation with Hot Reloading.",
|
||||
"homepage": "https://github.com/storybooks/storybook/tree/master/app/react",
|
||||
"bugs": {
|
||||
@ -22,16 +22,16 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/core": "4.0.0-alpha.4",
|
||||
"@storybook/core": "4.0.0-alpha.7",
|
||||
"@storybook/react-dev-utils": "^5.0.0",
|
||||
"airbnb-js-shims": "^1.4.1",
|
||||
"babel-loader": "^7.1.4",
|
||||
"babel-plugin-macros": "^2.2.0",
|
||||
"babel-plugin-macros": "^2.2.1",
|
||||
"babel-plugin-react-docgen": "^2.0.0-rc.0",
|
||||
"babel-plugin-transform-regenerator": "^6.26.0",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-preset-env": "^1.6.1",
|
||||
"babel-preset-minify": "^0.4.1",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"babel-preset-minify": "^0.4.2",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
"babel-preset-stage-0": "^6.24.1",
|
||||
"babel-runtime": "^6.26.0",
|
||||
@ -40,14 +40,14 @@
|
||||
"core-js": "^2.5.6",
|
||||
"dotenv-webpack": "^1.5.5",
|
||||
"glamor": "^2.20.40",
|
||||
"glamorous": "^4.12.5",
|
||||
"glamorous": "^4.13.0",
|
||||
"global": "^4.3.2",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"lodash.flattendeep": "^4.4.0",
|
||||
"prop-types": "^15.6.1",
|
||||
"raw-loader": "^0.5.1",
|
||||
"webpack": "^4.8.0",
|
||||
"webpack-hot-middleware": "^2.22.1"
|
||||
"webpack": "^4.8.3",
|
||||
"webpack-hot-middleware": "^2.22.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"babel-core": "^6.26.0 || ^7.0.0-0",
|
||||
|
@ -13,7 +13,14 @@ function render(node, el) {
|
||||
);
|
||||
}
|
||||
|
||||
export default function renderMain({ story, selectedKind, selectedStory, showMain, showError }) {
|
||||
export default function renderMain({
|
||||
story,
|
||||
selectedKind,
|
||||
selectedStory,
|
||||
showMain,
|
||||
showError,
|
||||
forceRender,
|
||||
}) {
|
||||
const element = story();
|
||||
|
||||
if (!element) {
|
||||
@ -42,7 +49,10 @@ export default function renderMain({ story, selectedKind, selectedStory, showMai
|
||||
// Otherwise, React may not recrease instances for every story run.
|
||||
// This could leads to issues like below:
|
||||
// https://github.com/storybooks/react-storybook/issues/81
|
||||
ReactDOM.unmountComponentAtNode(rootEl);
|
||||
// But forceRender means that it's the same story, so we want too keep the state in that case.
|
||||
if (!forceRender) {
|
||||
ReactDOM.unmountComponentAtNode(rootEl);
|
||||
}
|
||||
showMain();
|
||||
render(element, rootEl);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@storybook/vue",
|
||||
"version": "4.0.0-alpha.4",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "Storybook for Vue: Develop Vue Component in isolation with Hot Reloading.",
|
||||
"homepage": "https://github.com/storybooks/storybook/tree/master/apps/vue",
|
||||
"bugs": {
|
||||
@ -22,15 +22,15 @@
|
||||
"prepare": "node ../../scripts/prepare.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/core": "4.0.0-alpha.4",
|
||||
"@storybook/core": "4.0.0-alpha.7",
|
||||
"@storybook/react-dev-utils": "^5.0.0",
|
||||
"airbnb-js-shims": "^1.4.1",
|
||||
"babel-loader": "^7.1.4",
|
||||
"babel-plugin-macros": "^2.2.0",
|
||||
"babel-plugin-macros": "^2.2.1",
|
||||
"babel-plugin-transform-regenerator": "^6.26.0",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-preset-env": "^1.6.0",
|
||||
"babel-preset-minify": "^0.4.1",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"babel-preset-minify": "^0.4.2",
|
||||
"babel-preset-stage-0": "^6.24.1",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"case-sensitive-paths-webpack-plugin": "^2.1.2",
|
||||
@ -40,8 +40,8 @@
|
||||
"global": "^4.3.2",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"raw-loader": "^0.5.1",
|
||||
"webpack": "^4.8.0",
|
||||
"webpack-hot-middleware": "^2.22.1"
|
||||
"webpack": "^4.8.3",
|
||||
"webpack-hot-middleware": "^2.22.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vue": "^2.5.16",
|
||||
|
@ -18,13 +18,13 @@
|
||||
"storybook": "start-storybook -p 9009 -s src/pages"
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/addon-actions": "^3.4.3",
|
||||
"@storybook/addon-links": "^3.4.3",
|
||||
"@storybook/addons": "^3.4.3",
|
||||
"@storybook/react": "^3.4.3",
|
||||
"@storybook/addon-actions": "^3.4.4",
|
||||
"@storybook/addon-links": "^3.4.4",
|
||||
"@storybook/addons": "^3.4.4",
|
||||
"@storybook/react": "^3.4.4",
|
||||
"babel-loader": "^6.4.1",
|
||||
"bootstrap": "^3.3.7",
|
||||
"gatsby": "^1.9.259",
|
||||
"gatsby": "^1.9.260",
|
||||
"gatsby-link": "^1.6.44",
|
||||
"gatsby-plugin-sharp": "^1.6.44",
|
||||
"gatsby-remark-autolink-headers": "^1.4.18",
|
||||
@ -32,7 +32,7 @@
|
||||
"gatsby-remark-images": "^1.5.63",
|
||||
"gatsby-remark-smartypants": "^1.4.12",
|
||||
"gatsby-source-filesystem": "^1.5.35",
|
||||
"gatsby-transformer-remark": "^1.7.40",
|
||||
"gatsby-transformer-remark": "^1.7.41",
|
||||
"gh-pages": "^1.1.0",
|
||||
"global": "^4.3.2",
|
||||
"highlight.js": "^9.12.0",
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user