Merge remote-tracking branch 'origin/master' into release/3.3

# Conflicts:
#	addons/knobs/src/components/__tests__/Array.js
#	examples/cra-kitchen-sink/.storybook/addons.js
#	examples/cra-kitchen-sink/package.json
#	yarn.lock
This commit is contained in:
hypnos 2017-11-05 02:34:45 +03:00
commit c3d88932f0
21 changed files with 823 additions and 41 deletions

2
.github/stale.yml vendored
View File

@ -17,7 +17,7 @@ markComment: >
Hi everyone! Seems like there hasn't been much going on in this issue lately.
If there are still questions, comments, or bugs, please feel free to continue
the discussion. We do try to do some housekeeping every once in a while so
inactive issues will get closed after 90 days. Thanks!
inactive issues will get closed after 60 days. Thanks!
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: >
Hey there, it's me again! I am going to help our maintainers close this issue

View File

@ -0,0 +1,55 @@
# addon-backgrounds
[![Build Status](https://travis-ci.org/storybooks/addon-backgrounds.svg?branch=travis)](https://travis-ci.org/storybooks/addon-backgrounds)
![React Storybook Screenshot](./.storybook/backgrounds.gif)
### Getting Started
```sh
npm i --save @storybook/addon-backgrounds
```
Then create a file called `addons.js` in your storybook config.
Add following content to it:
```js
import '@storybook/addon-backgrounds/register';
```
Then write your stories like this:
```js
import React from 'react';
import { storiesOf } from "@storybook/react";
import backgrounds from "@storybook/addon-backgrounds";
storiesOf("Button", module)
.addDecorator(backgrounds([
{ name: "twitter", value: "#00aced", default: true },
{ name: "facebook", value: "#3b5998" },
]))
.add("with text", () => <button>Click me</button>);
```
### Development
This project is built using typescript and is tested with jest. To get started, clone this repo and run the following command:
```bash
$ npm install # install node deps
```
To run the project locally, run:
```bash
$ npm run storybook # for storybook testing
# (coming soon) $ npm run test-watch # for testing
```
To test the project run:
```bash
$ npm test
```

View File

@ -0,0 +1,32 @@
{
"name": "@storybook/addon-backgrounds",
"version": "3.2.14",
"description": "A storybook addon to show different backgrounds for your preview",
"keywords": [
"addon",
"background",
"react",
"storybook"
],
"homepage": "https://storybook.js.org",
"bugs": {
"url": "https://github.com/storybooks/storybook/issues"
},
"license": "MIT",
"author": "jbaxleyiii",
"main": "dist/index.js",
"repository": {
"type": "git",
"url": "https://github.com/storybooks/storybook.git"
},
"scripts": {
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"prop-types": "^15.6.0"
},
"peerDependencies": {
"@storybook/addons": "^3.2.14",
"react": "*"
}
}

View File

@ -0,0 +1 @@
require('./dist/register');

View File

@ -0,0 +1,125 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import addons from '@storybook/addons';
import EventEmitter from 'events';
import Swatch from './Swatch';
const style = {
font: {
fontFamily:
"-apple-system,'.SFNSText-Regular', 'San Francisco', Roboto, 'Segoe UI', 'Helvetica Neue', 'Lucida Grande', sans-serif",
fontSize: '14px',
},
};
const defaultBackground = {
name: 'default',
value: 'transparent',
};
const instructionsHtml = `
import { storiesOf } from "@storybook/react";
import backgrounds from "@storybook/addon-backgrounds";
storiesOf("First Component", module)
.addDecorator(backgrounds([
{ name: "twitter", value: "#00aced" },
{ name: "facebook", value: "#3b5998" },
]))
.add("First Button", () => <button>Click me</button>);
`.trim();
const Instructions = () => (
<div style={Object.assign({ padding: '20px' }, style.font)}>
<h5 style={{ fontSize: '16px' }}>Setup Instructions</h5>
<p>
Please add the background decorator definition to your story. The background decorate accepts
an array of items, which should include a name for your color (preferably the css class name)
and the corresponding color / image value.
</p>
<p>Below is an example of how to add the background decorator to your story definition.</p>
<pre
style={{
padding: '30px',
display: 'block',
background: 'rgba(19,19,19,0.9)',
color: 'rgba(255,255,255,0.95)',
marginTop: '15px',
lineHeight: '1.75em',
}}
>
<code>{instructionsHtml}</code>
</pre>
</div>
);
export default class BackgroundPanel extends Component {
constructor(props) {
super(props);
const { channel, api } = props;
// A channel is explicitly passed in for testing
if (channel) {
this.channel = channel;
} else {
this.channel = addons.getChannel();
}
this.state = { backgrounds: [] };
this.channel.on('background-set', backgrounds => {
this.setState({ backgrounds });
const currentBackground = api.getQueryParam('background');
if (currentBackground) {
this.setBackgroundInPreview(currentBackground);
} else if (backgrounds.filter(x => x.default).length) {
const defaultBgs = backgrounds.filter(x => x.default);
this.setBackgroundInPreview(defaultBgs[0].value);
}
});
this.channel.on('background-unset', () => {
this.setState({ backgrounds: [] });
api.setQueryParams({ background: null });
});
}
setBackgroundInPreview = background => this.channel.emit('background', background);
setBackgroundFromSwatch = background => {
this.setBackgroundInPreview(background);
this.props.api.setQueryParams({ background });
};
render() {
const backgrounds = [...this.state.backgrounds];
if (!backgrounds.length) return <Instructions />;
const hasDefault = backgrounds.filter(x => x.default).length;
if (!hasDefault) backgrounds.push(defaultBackground);
return (
<div style={{ display: 'inline-block', padding: '15px' }}>
{backgrounds.map(({ value, name }) => (
<div key={`${name} ${value}`} style={{ display: 'inline-block', padding: '5px' }}>
<Swatch value={value} name={name} setBackground={this.setBackgroundFromSwatch} />
</div>
))}
</div>
);
}
}
BackgroundPanel.propTypes = {
api: PropTypes.shape({
getQueryParam: PropTypes.func,
setQueryParams: PropTypes.func,
}).isRequired,
channel: PropTypes.instanceOf(EventEmitter),
};
BackgroundPanel.defaultProps = {
channel: undefined,
};

View File

@ -0,0 +1,65 @@
import React from 'react';
import PropTypes from 'prop-types';
const style = {
swatches: {
backgroundColor: '#fff',
textAlign: 'center',
padding: '0',
border: '1px solid rgba(0,0,0,0.1)',
borderRadius: '4px',
cursor: 'pointer',
display: 'inline-block',
width: '175px',
verticalAlign: 'top',
wordWrap: 'break-word',
},
swatch: {
height: '80px',
borderRadius: '4px 4px 0 0',
transition: 'opacity 0.25s ease-in-out',
borderBottom: '1px solid rgba(0,0,0,0.1)',
},
listStyle: { listStyle: 'none' },
pushBottom: { marginBottom: '10px' },
pushLeft: { marginLeft: '10px' },
soft: { paddingLeft: '10px', paddingRight: '10px' },
hard: { padding: '0' },
flush: { margin: '0' },
font: {
fontFamily:
"-apple-system, '.SFNSText-Regular', 'San Francisco', Roboto, 'Segoe UI', 'Helvetica Neue', 'Lucida Grande', sans-serif",
fontSize: '14px',
wordBreak: 'break-word',
},
};
const Swatch = ({ name, value, setBackground }) => (
<button
style={Object.assign({}, style.swatches, style.listStyle, style.hard)}
onClick={() => setBackground(value)}
// Prevent focusing on mousedown
onMouseDown={event => event.preventDefault()}
>
<div
style={Object.assign({}, style.swatch, {
background: value,
backgroundSize: 'cover',
backgroundPosition: 'center',
})}
/>
<div style={Object.assign({}, style.listStyle, style.soft)}>
<h4 style={Object.assign({ float: 'left', fontWeight: 'bold' }, style.font)}>{name}:</h4>
<h4 style={Object.assign({ float: 'right', fontWeight: 'normal' }, style.font)}>
<em>{value}</em>
</h4>
</div>
</button>
);
Swatch.propTypes = {
name: PropTypes.string.isRequired,
value: PropTypes.string.isRequired,
setBackground: PropTypes.func.isRequired,
};
export default Swatch;

View File

@ -0,0 +1,123 @@
import React from 'react';
import { shallow, mount } from 'enzyme';
import EventEmitter from 'events';
import BackgroundPanel from '../BackgroundPanel';
const backgrounds = [
{ name: 'black', value: '#000000' },
{ name: 'secondary', value: 'rgb(123,123,123)' },
{ name: 'tertiary', value: 'rgba(123,123,123,.5)' },
{ name: 'An image', value: 'url(http://placehold.it/350x150)' },
];
const mockedApi = {
getQueryParam: jest.fn(),
setQueryParams: jest.fn(),
};
const channel = new EventEmitter();
describe('Background Panel', () => {
it('should exist', () => {
const backgroundPanel = shallow(<BackgroundPanel channel={channel} api={mockedApi} />);
expect(backgroundPanel).toBeDefined();
});
it('should have a default background value of transparent', () => {
const backgroundPanel = shallow(<BackgroundPanel channel={channel} api={mockedApi} />);
expect(backgroundPanel.state().backgrounds.length).toBe(0);
});
it('should show setup instructions if no colors provided', () => {
const backgroundPanel = shallow(<BackgroundPanel channel={channel} api={mockedApi} />);
expect(backgroundPanel.html().match(/Setup Instructions/gim).length).toBeGreaterThan(0);
});
it('should set the query string', () => {
const SpiedChannel = new EventEmitter();
mount(<BackgroundPanel channel={SpiedChannel} api={mockedApi} />);
SpiedChannel.emit('background-set', backgrounds);
expect(mockedApi.getQueryParam).toBeCalledWith('background');
});
it('should unset the query string', () => {
const SpiedChannel = new EventEmitter();
mount(<BackgroundPanel channel={SpiedChannel} api={mockedApi} />);
SpiedChannel.emit('background-unset', []);
expect(mockedApi.setQueryParams).toBeCalledWith({ background: null });
});
it('should accept colors through channel and render the correct swatches with a default swatch', () => {
const SpiedChannel = new EventEmitter();
const backgroundPanel = mount(<BackgroundPanel channel={SpiedChannel} api={mockedApi} />);
SpiedChannel.emit('background-set', backgrounds);
expect(backgroundPanel.state('backgrounds')).toEqual(backgrounds);
});
it('should allow setting a default swatch', () => {
const SpiedChannel = new EventEmitter();
const backgroundPanel = mount(<BackgroundPanel channel={SpiedChannel} api={mockedApi} />);
const [head, ...tail] = backgrounds;
const localBgs = [{ ...head, default: true }, ...tail];
SpiedChannel.emit('background-set', localBgs);
expect(backgroundPanel.state('backgrounds')).toEqual(localBgs);
backgroundPanel.setState({ backgrounds: localBgs }); // force re-render
// check to make sure the default bg was added
const headings = backgroundPanel.find('h4');
expect(headings.length).toBe(8);
});
it('should allow the default swatch become the background color', () => {
const SpiedChannel = new EventEmitter();
const backgroundPanel = mount(<BackgroundPanel channel={SpiedChannel} api={mockedApi} />);
const [head, second, ...tail] = backgrounds;
const localBgs = [head, { ...second, default: true }, ...tail];
SpiedChannel.on('background', bg => {
expect(bg).toBe(second.value);
});
SpiedChannel.emit('background-set', localBgs);
expect(backgroundPanel.state('backgrounds')).toEqual(localBgs);
backgroundPanel.setState({ backgrounds: localBgs }); // force re-render
// check to make sure the default bg was added
const headings = backgroundPanel.find('h4');
expect(headings.length).toBe(8);
});
it('should unset all swatches on receiving the background-unset message', () => {
const SpiedChannel = new EventEmitter();
const backgroundPanel = mount(<BackgroundPanel channel={SpiedChannel} api={mockedApi} />);
SpiedChannel.emit('background-set', backgrounds);
expect(backgroundPanel.state('backgrounds')).toEqual(backgrounds);
backgroundPanel.setState({ backgrounds }); // force re-render
SpiedChannel.emit('background-unset');
expect(backgroundPanel.state('backgrounds')).toHaveLength(0);
});
it('should pass the event from swatch clicks through the provided channel', () => {
const SpiedChannel = new EventEmitter();
const backgroundPanel = mount(<BackgroundPanel channel={SpiedChannel} api={mockedApi} />);
backgroundPanel.setState({ backgrounds }); // force re-render
const spy = jest.fn();
SpiedChannel.on('background', spy);
backgroundPanel
.find('h4')
.first()
.simulate('click');
expect(spy).toBeCalledWith(backgrounds[0].value);
});
});

View File

@ -0,0 +1,39 @@
import React from 'react';
import { shallow, mount } from 'enzyme';
import Swatch from '../Swatch';
const mockedSetBackround = jest.fn();
describe('Swatch', () => {
it('should exist', () => {
const swatch = shallow(<Swatch value="bar" name="foo" setBackground={mockedSetBackround} />);
expect(swatch).toBeDefined();
});
it('should render the name of the swatch', () => {
const markup = shallow(
<Swatch value="bar" name="foo" setBackground={mockedSetBackround} />
).html();
expect(markup.match(/foo/gim).length).toBe(1);
});
it('should render the value of the swatch and set it to be the background', () => {
const markup = shallow(
<Swatch value="bar" name="foo" setBackground={mockedSetBackround} />
).html();
expect(markup.match(/background:bar/gim).length).toBe(1);
expect(markup.match(/bar/gim).length).toBe(2);
});
it('should emit message on click', () => {
const spy = jest.fn();
const swatch = mount(<Swatch value="#e6e6e6" name="Gray" setBackground={spy} />);
swatch.simulate('click');
expect(spy).toBeCalledWith('#e6e6e6');
});
});

View File

@ -0,0 +1,92 @@
import React from 'react';
import { shallow } from 'enzyme';
import { BackgroundDecorator } from '../index';
const EventEmitter = require('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 initially have a transparent background state', () => {
const SpiedChannel = new EventEmitter();
const backgroundDecorator = shallow(
<BackgroundDecorator story={testStory} channel={SpiedChannel} />
);
expect(backgroundDecorator.state().background).toBe('transparent');
});
it('should have a background matching its state', () => {
const SpiedChannel = new EventEmitter();
const backgroundDecorator = shallow(
<BackgroundDecorator story={testStory} channel={SpiedChannel} />
);
expect(backgroundDecorator.html().match(/background:transparent/gim).length).toBe(1);
});
it('should set internal state when background event called', () => {
const SpiedChannel = new EventEmitter();
const backgroundDecorator = shallow(
<BackgroundDecorator story={testStory} channel={SpiedChannel} />
);
SpiedChannel.emit('background', '#123456');
expect(backgroundDecorator.state().background).toBe('#123456');
});
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('background-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('background-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.length).toBe(1);
});
});

View File

@ -0,0 +1,76 @@
import React from 'react';
import PropTypes from 'prop-types';
import EventEmitter from 'events';
import addons from '@storybook/addons';
const style = {
wrapper: {
overflow: 'scroll',
position: 'fixed',
top: 0,
bottom: 0,
right: 0,
left: 0,
transition: 'background 0.25s ease-in-out',
backgroundPosition: 'center',
backgroundSize: 'cover',
background: 'transparent',
},
};
export class BackgroundDecorator extends React.Component {
constructor(props) {
super(props);
const { channel, story } = props;
// A channel is explicitly passed in for testing
if (channel) {
this.channel = channel;
} else {
this.channel = addons.getChannel();
}
this.state = { background: 'transparent' };
this.story = story();
}
componentWillMount() {
this.channel.on('background', this.setBackground);
this.channel.emit('background-set', this.props.backgrounds);
}
componentWillReceiveProps(nextProps) {
if (nextProps.story !== this.props.story) {
this.story = nextProps.story();
}
}
componentWillUnmount() {
this.channel.removeListener('background', this.setBackground);
this.channel.emit('background-unset');
}
setBackground = background => this.setState({ background });
render() {
const styles = style.wrapper;
styles.background = this.state.background;
return <div style={Object.assign({}, styles)}>{this.story}</div>;
}
}
BackgroundDecorator.propTypes = {
backgrounds: PropTypes.arrayOf(PropTypes.object),
channel: PropTypes.instanceOf(EventEmitter),
story: PropTypes.func.isRequired,
};
BackgroundDecorator.defaultProps = {
backgrounds: [],
channel: undefined,
};
export default backgrounds => story => (
<BackgroundDecorator story={story} backgrounds={backgrounds} />
);

View File

@ -0,0 +1,15 @@
import React from 'react';
import addons from '@storybook/addons';
import BackgroundPanel from './BackgroundPanel';
const ADDON_ID = 'storybook-addon-background';
const PANEL_ID = `${ADDON_ID}/background-panel`;
addons.register(ADDON_ID, api => {
const channel = addons.getChannel();
addons.addPanel(PANEL_ID, {
title: 'Backgrounds',
render: () => <BackgroundPanel channel={channel} api={api} />,
});
});

View File

@ -35,7 +35,14 @@ import { withInfo } from '@storybook/addon-info';
storiesOf('Component', module)
.add('simple info',
withInfo('description or documentation about my component, supports markdown')(() =>
withInfo(`
description or documentation about my component, supports markdown
~~~js
<Button>Click Here</Button>
~~~
`)(() =>
<Component>Click the "?" mark at top-right to view the info.</Component>
)
)
@ -81,6 +88,14 @@ import { setDefaults } from '@storybook/addon-info';
// addon-info
setDefaults({
header: false, // Toggles display of header with component name and description
});
```
## Options and Defaults
```js
{
header: false, // Toggles display of header with component name and description
inline: true, // Displays info inline vs click button to view
source: true, // Displays the source of story Component
propTables: [/* Components used in story */], // displays Prop Tables with this components
@ -88,10 +103,10 @@ setDefaults({
styles: {}, // Overrides styles of addon
marksyConf: {}, // Overrides components used to display markdown. Warning! This option's name will be likely deprecated in favor to "components" with the same API in 3.3 release. Follow this PR #1501 for details
maxPropsIntoLine: 1, // Max props to display per line in source code
maxPropObjectKeys: 10,
maxPropArrayLength: 10,
maxPropStringLength: 100,
});
maxPropObjectKeys: 10, // Displays the first 10 characters of the prop name
maxPropArrayLength: 10, // Displays the first 10 items in the default prop array
maxPropStringLength: 100, // Displays the first 100 characters in the default prop string
}
```
## Deprecated usage

View File

@ -5,16 +5,16 @@ Array [
<span>
foo
</span>,
</span>,
<span>
<br />
bar
</span>,
</span>,
<span>
<br />
baz
</span>,
</span>,
]
`;

View File

@ -1,12 +1,12 @@
import React from 'react';
import { shallow } from 'enzyme'; // eslint-disable-line
import Array from '../types/Array';
import ArrayType from '../types/Array';
describe('Array', () => {
it('should subscribe to setKnobs event of channel', () => {
const onChange = jest.fn();
const wrapper = shallow(
<Array
<ArrayType
onChange={onChange}
knob={{ name: 'passions', value: ['Fishing', 'Skiing'], separator: ',' }}
/>
@ -16,10 +16,25 @@ describe('Array', () => {
expect(onChange).toHaveBeenCalledWith(['Fhishing', 'Skiing', 'Dancing']);
});
it('deserializes an Array to an Array', () => {
const array = ['a', 'b', 'c'];
const deserialized = ArrayType.deserialize(array);
expect(deserialized).toEqual(['a', 'b', 'c']);
});
it('deserializes an Object to an Array', () => {
const object = { 1: 'one', 0: 'zero', 2: 'two' };
const deserialized = ArrayType.deserialize(object);
expect(deserialized).toEqual(['zero', 'one', 'two']);
});
it('should change to an empty array when emptied', () => {
const onChange = jest.fn();
const wrapper = shallow(
<Array
<ArrayType
onChange={onChange}
knob={{ name: 'passions', value: ['Fishing', 'Skiing'], separator: ',' }}
/>

View File

@ -54,6 +54,12 @@ ArrayType.propTypes = {
};
ArrayType.serialize = value => value;
ArrayType.deserialize = value => value;
ArrayType.deserialize = value => {
if (Array.isArray(value)) return value;
return Object.keys(value)
.sort()
.reduce((array, key) => [...array, value[key]], []);
};
export default ArrayType;

View File

@ -4,4 +4,5 @@ import '@storybook/addon-events/register';
import '@storybook/addon-notes/register';
import '@storybook/addon-options/register';
import '@storybook/addon-knobs/register';
import '@storybook/addon-backgrounds/register';
import '@storybook/addon-viewport/register';

View File

@ -22,6 +22,7 @@
},
"devDependencies": {
"@storybook/addon-actions": "3.3.0-alpha.2",
"@storybook/addon-backgrounds": "^3.2.14",
"@storybook/addon-centered": "3.3.0-alpha.2",
"@storybook/addon-events": "3.3.0-alpha.2",
"@storybook/addon-info": "3.3.0-alpha.2",

View File

@ -0,0 +1,53 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Storyshots Addon Backgrounds story 1 1`] = `
<div
style={
Object {
"background": "transparent",
"backgroundPosition": "center",
"backgroundSize": "cover",
"bottom": 0,
"left": 0,
"overflow": "scroll",
"position": "fixed",
"right": 0,
"top": 0,
"transition": "background 0.25s ease-in-out",
}
}
>
<button
disabled={false}
onClick={[Function]}
>
You should be able to switch backgrounds for this story
</button>
</div>
`;
exports[`Storyshots Addon Backgrounds story 2 1`] = `
<div
style={
Object {
"background": "transparent",
"backgroundPosition": "center",
"backgroundSize": "cover",
"bottom": 0,
"left": 0,
"overflow": "scroll",
"position": "fixed",
"right": 0,
"top": 0,
"transition": "background 0.25s ease-in-out",
}
}
>
<button
disabled={false}
onClick={[Function]}
>
This one too!
</button>
</div>
`;

View File

@ -0,0 +1,17 @@
import React from 'react';
import { storiesOf } from '@storybook/react';
import backgrounds from '@storybook/addon-backgrounds';
import BaseButton from '../components/BaseButton';
storiesOf('Addon Backgrounds', module)
.addDecorator(
backgrounds([
{ name: 'twitter', value: '#00aced' },
{ name: 'facebook', value: '#3b5998', default: true },
])
)
.add('story 1', () => (
<BaseButton label="You should be able to switch backgrounds for this story" />
))
.add('story 2', () => <BaseButton label="This one too!" />);

View File

@ -72,6 +72,7 @@
"husky": "^0.14.3",
"inquirer": "^3.2.3",
"jest": "^21.2.0",
"jest-cli": "^21.2.1",
"jest-enzyme": "^4.0.1",
"jest-image-snapshot": "^2.1.0",
"lerna": "^2.4.0",

106
yarn.lock
View File

@ -282,10 +282,14 @@ acorn@^4.0.3, acorn@^4.0.4:
version "4.0.13"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787"
acorn@^5.0.0, acorn@^5.1.1:
acorn@^5.0.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.2.1.tgz#317ac7821826c22c702d66189ab8359675f135d7"
acorn@^5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.2.tgz#911cb53e036807cf0fa778dc5d370fbd864246d7"
add-stream@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa"
@ -344,10 +348,14 @@ ajv-keywords@^1.0.0:
version "1.5.1"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
ajv-keywords@^2.0.0, ajv-keywords@^2.1.0:
ajv-keywords@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762"
ajv-keywords@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.0.tgz#a296e17f7bfae7c1ce4f7e0de53d29cb32162df0"
ajv@^4.7.0, ajv@^4.9.1:
version "4.11.8"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536"
@ -355,7 +363,7 @@ ajv@^4.7.0, ajv@^4.9.1:
co "^4.6.0"
json-stable-stringify "^1.0.1"
ajv@^5.0.0, ajv@^5.1.0, ajv@^5.1.5, ajv@^5.2.0, ajv@^5.2.3:
ajv@^5.0.0, ajv@^5.1.5:
version "5.3.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.3.0.tgz#4414ff74a50879c208ee5fdc826e32c303549eda"
dependencies:
@ -364,6 +372,15 @@ ajv@^5.0.0, ajv@^5.1.0, ajv@^5.1.5, ajv@^5.2.0, ajv@^5.2.3:
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.3.0"
ajv@^5.1.0, ajv@^5.2.0, ajv@^5.2.3:
version "5.2.3"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.2.3.tgz#c06f598778c44c6b161abafe3466b81ad1814ed2"
dependencies:
co "^4.6.0"
fast-deep-equal "^1.0.0"
json-schema-traverse "^0.3.0"
json-stable-stringify "^1.0.1"
align-text@^0.1.1, align-text@^0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
@ -2486,11 +2503,11 @@ browserslist@^2.1.5:
electron-to-chromium "^1.3.27"
browserslist@^2.5.1:
version "2.5.1"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.5.1.tgz#68e4bc536bbcc6086d62843a2ffccea8396821c6"
version "2.7.0"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.7.0.tgz#dc375dc70048fec3d989042a35022342902eff00"
dependencies:
caniuse-lite "^1.0.30000744"
electron-to-chromium "^1.3.24"
caniuse-lite "^1.0.30000757"
electron-to-chromium "^1.3.27"
bser@1.0.2:
version "1.0.2"
@ -2646,10 +2663,10 @@ caniuse-api@^1.5.2:
lodash.uniq "^4.5.0"
caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
version "1.0.30000749"
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000749.tgz#556773aa3aa704f581d748fa63b46ca087aac67d"
version "1.0.30000757"
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000757.tgz#fa23a383213d857f4a1e6a3bee17b32668504cbf"
caniuse-lite@^1.0.30000697, caniuse-lite@^1.0.30000744, caniuse-lite@^1.0.30000755:
caniuse-lite@^1.0.30000697, caniuse-lite@^1.0.30000755:
version "1.0.30000756"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000756.tgz#3da701c1521b9fab87004c6de7c97fa47dbeaad2"
@ -2657,9 +2674,9 @@ caniuse-lite@^1.0.30000718:
version "1.0.30000740"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000740.tgz#f2c4c04d6564eb812e61006841700ad557f6f973"
caniuse-lite@^1.0.30000748:
version "1.0.30000749"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000749.tgz#2ff382865aead8cca35dacfbab04f58effa4c01c"
caniuse-lite@^1.0.30000748, caniuse-lite@^1.0.30000757:
version "1.0.30000757"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000757.tgz#81e3bc029728a032933501994ef79db1c21159e3"
capture-stack-trace@^1.0.0:
version "1.0.0"
@ -3422,6 +3439,14 @@ copy-concurrently@^1.0.0:
rimraf "^2.5.4"
run-queue "^1.0.0"
copy-paste@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/copy-paste/-/copy-paste-1.3.0.tgz#a7e6c4a1c28fdedf2b081e72b97df2ef95f471ed"
dependencies:
iconv-lite "^0.4.8"
optionalDependencies:
sync-exec "~0.6.x"
core-js@^1.0.0:
version "1.2.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
@ -4207,7 +4232,7 @@ ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.18, electron-to-chromium@^1.3.24, electron-to-chromium@^1.3.27:
electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.18, electron-to-chromium@^1.3.27:
version "1.3.27"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.27.tgz#78ecb8a399066187bb374eede35d9c70565a803d"
@ -4330,9 +4355,10 @@ entities@^1.1.1, entities@~1.1.1:
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"
envinfo@^3.0.0:
version "3.4.2"
resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-3.4.2.tgz#f06648836155b81e1d7b4a1c3fca3f6b5f38789b"
version "3.5.0"
resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-3.5.0.tgz#2c88fb33a0223c19f42ced23c4cf223393d236e7"
dependencies:
copy-paste "^1.3.0"
minimist "^1.2.0"
os-name "^2.0.1"
which "^1.2.14"
@ -5338,8 +5364,8 @@ flatten@^1.0.2:
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
flow-parser@^0.*:
version "0.57.3"
resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.57.3.tgz#b8d241a1b1cbae043afa7976e39f269988d8fe34"
version "0.58.0"
resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.58.0.tgz#f932b5e25fd503f2ad5c2e39445983936e41706b"
flush-write-stream@^1.0.0:
version "1.0.2"
@ -6431,7 +6457,7 @@ iconv-lite@0.4.13:
version "0.4.13"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
iconv-lite@0.4.19, iconv-lite@^0.4.17, iconv-lite@^0.4.5, iconv-lite@~0.4.13:
iconv-lite@0.4.19, iconv-lite@^0.4.17, iconv-lite@^0.4.5, iconv-lite@^0.4.8, iconv-lite@~0.4.13:
version "0.4.19"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
@ -7857,6 +7883,10 @@ keycode@^2.1.8:
version "2.1.9"
resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.1.9.tgz#964a23c54e4889405b4861a5c9f0480d45141dfa"
killable@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.0.tgz#da8b84bd47de5395878f95d64d02f2449fe05e6b"
kind-of@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-2.0.1.tgz#018ec7a4ce7e3a86cb9141be519d24c8faa981b5"
@ -10364,7 +10394,15 @@ postcss@^5.0.0, postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.
source-map "^0.5.6"
supports-color "^3.2.3"
postcss@^6.0.0, postcss@^6.0.1, postcss@^6.0.13, postcss@^6.0.2, postcss@^6.0.6, postcss@^6.0.8:
postcss@^6.0.0, postcss@^6.0.1, postcss@^6.0.13, postcss@^6.0.8:
version "6.0.14"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.14.tgz#5534c72114739e75d0afcf017db853099f562885"
dependencies:
chalk "^2.3.0"
source-map "^0.6.1"
supports-color "^4.4.0"
postcss@^6.0.2, postcss@^6.0.6:
version "6.0.13"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.13.tgz#b9ecab4ee00c89db3ec931145bd9590bbf3f125f"
dependencies:
@ -11068,8 +11106,8 @@ react-transition-group@^1.1.2:
warning "^3.0.0"
react-treebeard@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/react-treebeard/-/react-treebeard-2.0.3.tgz#cd644209c1be2fe2be3ae4bca8350ed6abf293d6"
version "2.1.0"
resolved "https://registry.yarnpkg.com/react-treebeard/-/react-treebeard-2.1.0.tgz#fbd5cf51089b6f09a9b18350ab3bddf736e57800"
dependencies:
babel-runtime "^6.23.0"
deep-equal "^1.0.1"
@ -11797,7 +11835,7 @@ require-uncached@^1.0.2, require-uncached@^1.0.3:
caller-path "^0.1.0"
resolve-from "^1.0.0"
requires-port@1.0.x, requires-port@1.x.x:
requires-port@1.0.x, requires-port@1.x.x, requires-port@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
@ -12974,6 +13012,10 @@ symlink-dir@^1.1.0:
mkdirp-promise "^5.0.0"
mz "^2.4.0"
sync-exec@~0.6.x:
version "0.6.2"
resolved "https://registry.yarnpkg.com/sync-exec/-/sync-exec-0.6.2.tgz#717d22cc53f0ce1def5594362f3a89a2ebb91105"
table@^3.7.8:
version "3.8.3"
resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f"
@ -13676,13 +13718,20 @@ url-parse@1.0.x:
querystringify "0.0.x"
requires-port "1.0.x"
url-parse@^1.1.1, url-parse@^1.1.8, url-parse@^1.1.9:
url-parse@^1.1.1:
version "1.1.9"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.1.9.tgz#c67f1d775d51f0a18911dd7b3ffad27bb9e5bd19"
dependencies:
querystringify "~1.0.0"
requires-port "1.0.x"
url-parse@^1.1.8, url-parse@^1.1.9:
version "1.2.0"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.2.0.tgz#3a19e8aaa6d023ddd27dcc44cb4fc8f7fec23986"
dependencies:
querystringify "~1.0.0"
requires-port "~1.0.0"
url@^0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
@ -13912,8 +13961,8 @@ vue@^2.5.2:
resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.2.tgz#fd367a87bae7535e47f9dc5c9ec3b496e5feb5a4"
vuex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.0.0.tgz#98b4b5c4954b1c1c1f5b29fa0476a23580315814"
version "3.0.1"
resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.0.1.tgz#e761352ebe0af537d4bb755a9b9dc4be3df7efd2"
walk-sync@^0.3.1:
version "0.3.2"
@ -14036,8 +14085,8 @@ webpack-dev-server@2.8.2:
yargs "^6.6.0"
webpack-dev-server@^2.9.3:
version "2.9.3"
resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-2.9.3.tgz#f0554e88d129e87796a6f74a016b991743ca6f81"
version "2.9.4"
resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-2.9.4.tgz#7883e61759c6a4b33e9b19ec4037bd4ab61428d1"
dependencies:
ansi-html "0.0.7"
array-includes "^3.0.3"
@ -14053,6 +14102,7 @@ webpack-dev-server@^2.9.3:
import-local "^0.1.1"
internal-ip "1.2.0"
ip "^1.1.5"
killable "^1.0.0"
loglevel "^1.4.1"
opn "^5.1.0"
portfinder "^1.0.9"