Fix #372 - Emoji picker
This commit is contained in:
parent
6a1b738e0b
commit
89fc2d7f48
8 changed files with 315 additions and 11 deletions
|
@ -28,6 +28,8 @@ export const COMPOSE_SPOILER_TEXT_CHANGE = 'COMPOSE_SPOILER_TEXT_CHANGE';
|
||||||
export const COMPOSE_VISIBILITY_CHANGE = 'COMPOSE_VISIBILITY_CHANGE';
|
export const COMPOSE_VISIBILITY_CHANGE = 'COMPOSE_VISIBILITY_CHANGE';
|
||||||
export const COMPOSE_LISTABILITY_CHANGE = 'COMPOSE_LISTABILITY_CHANGE';
|
export const COMPOSE_LISTABILITY_CHANGE = 'COMPOSE_LISTABILITY_CHANGE';
|
||||||
|
|
||||||
|
export const COMPOSE_EMOJI_INSERT = 'COMPOSE_EMOJI_INSERT';
|
||||||
|
|
||||||
export function changeCompose(text) {
|
export function changeCompose(text) {
|
||||||
return {
|
return {
|
||||||
type: COMPOSE_CHANGE,
|
type: COMPOSE_CHANGE,
|
||||||
|
@ -260,3 +262,11 @@ export function changeComposeListability(checked) {
|
||||||
checked
|
checked
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function insertEmojiCompose(position, emoji) {
|
||||||
|
return {
|
||||||
|
type: COMPOSE_EMOJI_INSERT,
|
||||||
|
position,
|
||||||
|
emoji
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -15,6 +15,7 @@ import UnlistedToggleContainer from '../containers/unlisted_toggle_container';
|
||||||
import SpoilerToggleContainer from '../containers/spoiler_toggle_container';
|
import SpoilerToggleContainer from '../containers/spoiler_toggle_container';
|
||||||
import PrivateToggleContainer from '../containers/private_toggle_container';
|
import PrivateToggleContainer from '../containers/private_toggle_container';
|
||||||
import SensitiveToggleContainer from '../containers/sensitive_toggle_container';
|
import SensitiveToggleContainer from '../containers/sensitive_toggle_container';
|
||||||
|
import EmojiPickerDropdown from './emoji_picker_dropdown';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
placeholder: { id: 'compose_form.placeholder', defaultMessage: 'What is on your mind?' },
|
placeholder: { id: 'compose_form.placeholder', defaultMessage: 'What is on your mind?' },
|
||||||
|
@ -48,6 +49,7 @@ const ComposeForm = React.createClass({
|
||||||
onSuggestionSelected: React.PropTypes.func.isRequired,
|
onSuggestionSelected: React.PropTypes.func.isRequired,
|
||||||
onChangeSpoilerText: React.PropTypes.func.isRequired,
|
onChangeSpoilerText: React.PropTypes.func.isRequired,
|
||||||
onPaste: React.PropTypes.func.isRequired,
|
onPaste: React.PropTypes.func.isRequired,
|
||||||
|
onPickEmoji: React.PropTypes.func.isRequired
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
mixins: [PureRenderMixin],
|
||||||
|
@ -76,6 +78,7 @@ const ComposeForm = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
onSuggestionSelected (tokenStart, token, value) {
|
onSuggestionSelected (tokenStart, token, value) {
|
||||||
|
this._restoreCaret = null;
|
||||||
this.props.onSuggestionSelected(tokenStart, token, value);
|
this.props.onSuggestionSelected(tokenStart, token, value);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -88,8 +91,18 @@ const ComposeForm = React.createClass({
|
||||||
// If replying to zero or one users, places the cursor at the end of the textbox.
|
// If replying to zero or one users, places the cursor at the end of the textbox.
|
||||||
// If replying to more than one user, selects any usernames past the first;
|
// If replying to more than one user, selects any usernames past the first;
|
||||||
// this provides a convenient shortcut to drop everyone else from the conversation.
|
// this provides a convenient shortcut to drop everyone else from the conversation.
|
||||||
const selectionEnd = this.props.text.length;
|
let selectionEnd, selectionStart;
|
||||||
const selectionStart = (this.props.preselectDate !== prevProps.preselectDate) ? (this.props.text.search(/\s/) + 1) : selectionEnd;
|
|
||||||
|
if (this.props.preselectDate !== prevProps.preselectDate) {
|
||||||
|
selectionEnd = this.props.text.length;
|
||||||
|
selectionStart = this.props.text.search(/\s/) + 1;
|
||||||
|
} else if (typeof this._restoreCaret === 'number') {
|
||||||
|
selectionStart = this._restoreCaret;
|
||||||
|
selectionEnd = this._restoreCaret;
|
||||||
|
} else {
|
||||||
|
selectionEnd = this.props.text.length;
|
||||||
|
selectionStart = selectionEnd;
|
||||||
|
}
|
||||||
|
|
||||||
this.autosuggestTextarea.textarea.setSelectionRange(selectionStart, selectionEnd);
|
this.autosuggestTextarea.textarea.setSelectionRange(selectionStart, selectionEnd);
|
||||||
this.autosuggestTextarea.textarea.focus();
|
this.autosuggestTextarea.textarea.focus();
|
||||||
|
@ -100,6 +113,12 @@ const ComposeForm = React.createClass({
|
||||||
this.autosuggestTextarea = c;
|
this.autosuggestTextarea = c;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleEmojiPick (data) {
|
||||||
|
const position = this.autosuggestTextarea.textarea.selectionStart;
|
||||||
|
this._restoreCaret = position + data.shortname.length + 1;
|
||||||
|
this.props.onPickEmoji(position, data);
|
||||||
|
},
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { intl, needsPrivacyWarning, mentionedDomains, onPaste } = this.props;
|
const { intl, needsPrivacyWarning, mentionedDomains, onPaste } = this.props;
|
||||||
const disabled = this.props.is_submitting || this.props.is_uploading;
|
const disabled = this.props.is_submitting || this.props.is_uploading;
|
||||||
|
@ -156,7 +175,10 @@ const ComposeForm = React.createClass({
|
||||||
<div style={{ marginTop: '10px', overflow: 'hidden' }}>
|
<div style={{ marginTop: '10px', overflow: 'hidden' }}>
|
||||||
<div style={{ float: 'right' }}><Button text={publishText} onClick={this.handleSubmit} disabled={disabled} /></div>
|
<div style={{ float: 'right' }}><Button text={publishText} onClick={this.handleSubmit} disabled={disabled} /></div>
|
||||||
<div style={{ float: 'right', marginRight: '16px', lineHeight: '36px' }}><CharacterCounter max={500} text={[this.props.spoiler_text, this.props.text].join('')} /></div>
|
<div style={{ float: 'right', marginRight: '16px', lineHeight: '36px' }}><CharacterCounter max={500} text={[this.props.spoiler_text, this.props.text].join('')} /></div>
|
||||||
<UploadButtonContainer style={{ paddingTop: '4px' }} />
|
<div style={{ display: 'flex', paddingTop: '4px' }}>
|
||||||
|
<UploadButtonContainer />
|
||||||
|
<EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SpoilerToggleContainer />
|
<SpoilerToggleContainer />
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
import Dropdown, { DropdownTrigger, DropdownContent } from 'react-simple-dropdown';
|
||||||
|
import EmojiPicker from 'emojione-picker';
|
||||||
|
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||||
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
emoji: { id: 'emoji_button.label', defaultMessage: 'Emoji' }
|
||||||
|
});
|
||||||
|
|
||||||
|
const settings = {
|
||||||
|
imageType: 'png',
|
||||||
|
sprites: false,
|
||||||
|
imagePathPNG: '/emoji/'
|
||||||
|
};
|
||||||
|
|
||||||
|
const EmojiPickerDropdown = React.createClass({
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
intl: React.PropTypes.object.isRequired,
|
||||||
|
onPickEmoji: React.PropTypes.func.isRequired
|
||||||
|
},
|
||||||
|
|
||||||
|
mixins: [PureRenderMixin],
|
||||||
|
|
||||||
|
setRef (c) {
|
||||||
|
this.dropdown = c;
|
||||||
|
},
|
||||||
|
|
||||||
|
handleChange (data) {
|
||||||
|
this.dropdown.hide();
|
||||||
|
this.props.onPickEmoji(data);
|
||||||
|
},
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { intl } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dropdown ref={this.setRef} style={{ marginLeft: '5px' }}>
|
||||||
|
<DropdownTrigger className='icon-button' title={intl.formatMessage(messages.emoji)} style={{ fontSize: `24px`, width: `24px`, lineHeight: `24px`, marginTop: '-1px', display: 'block', marginLeft: '2px' }}>
|
||||||
|
<i className={`fa fa-smile-o`} style={{ verticalAlign: 'middle' }} />
|
||||||
|
</DropdownTrigger>
|
||||||
|
|
||||||
|
<DropdownContent>
|
||||||
|
<EmojiPicker emojione={settings} onChange={this.handleChange} />
|
||||||
|
</DropdownContent>
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
export default injectIntl(EmojiPickerDropdown);
|
|
@ -9,6 +9,7 @@ import {
|
||||||
fetchComposeSuggestions,
|
fetchComposeSuggestions,
|
||||||
selectComposeSuggestion,
|
selectComposeSuggestion,
|
||||||
changeComposeSpoilerText,
|
changeComposeSpoilerText,
|
||||||
|
insertEmojiCompose
|
||||||
} from '../../../actions/compose';
|
} from '../../../actions/compose';
|
||||||
|
|
||||||
const getMentionedUsernames = createSelector(state => state.getIn(['compose', 'text']), text => text.match(/(?:^|[^\/\w])@([a-z0-9_]+@[a-z0-9\.\-]+)/ig));
|
const getMentionedUsernames = createSelector(state => state.getIn(['compose', 'text']), text => text.match(/(?:^|[^\/\w])@([a-z0-9_]+@[a-z0-9\.\-]+)/ig));
|
||||||
|
@ -70,6 +71,10 @@ const mapDispatchToProps = (dispatch) => ({
|
||||||
dispatch(uploadCompose(files));
|
dispatch(uploadCompose(files));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onPickEmoji (position, data) {
|
||||||
|
dispatch(insertEmojiCompose(position, data));
|
||||||
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(ComposeForm);
|
export default connect(mapStateToProps, mapDispatchToProps)(ComposeForm);
|
||||||
|
|
|
@ -20,7 +20,8 @@ import {
|
||||||
COMPOSE_SPOILERNESS_CHANGE,
|
COMPOSE_SPOILERNESS_CHANGE,
|
||||||
COMPOSE_SPOILER_TEXT_CHANGE,
|
COMPOSE_SPOILER_TEXT_CHANGE,
|
||||||
COMPOSE_VISIBILITY_CHANGE,
|
COMPOSE_VISIBILITY_CHANGE,
|
||||||
COMPOSE_LISTABILITY_CHANGE
|
COMPOSE_LISTABILITY_CHANGE,
|
||||||
|
COMPOSE_EMOJI_INSERT
|
||||||
} from '../actions/compose';
|
} from '../actions/compose';
|
||||||
import { TIMELINE_DELETE } from '../actions/timelines';
|
import { TIMELINE_DELETE } from '../actions/timelines';
|
||||||
import { STORE_HYDRATE } from '../actions/store';
|
import { STORE_HYDRATE } from '../actions/store';
|
||||||
|
@ -105,6 +106,15 @@ const insertSuggestion = (state, position, token, completion) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const insertEmoji = (state, position, emojiData) => {
|
||||||
|
const emoji = emojiData.shortname;
|
||||||
|
|
||||||
|
return state.withMutations(map => {
|
||||||
|
map.update('text', oldText => `${oldText.slice(0, position)}${emoji} ${oldText.slice(position)}`);
|
||||||
|
map.set('focusDate', new Date());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export default function compose(state = initialState, action) {
|
export default function compose(state = initialState, action) {
|
||||||
switch(action.type) {
|
switch(action.type) {
|
||||||
case STORE_HYDRATE:
|
case STORE_HYDRATE:
|
||||||
|
@ -177,6 +187,8 @@ export default function compose(state = initialState, action) {
|
||||||
} else {
|
} else {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
case COMPOSE_EMOJI_INSERT:
|
||||||
|
return insertEmoji(state, action.position, action.emoji);
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropdown--active .icon-button {
|
||||||
|
color: $color4;
|
||||||
|
}
|
||||||
|
|
||||||
.invisible {
|
.invisible {
|
||||||
font-size: 0;
|
font-size: 0;
|
||||||
line-height: 0;
|
line-height: 0;
|
||||||
|
@ -547,7 +551,7 @@ a.status__content__spoiler-link {
|
||||||
left: 8px;
|
left: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
& > ul {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
background: $color2;
|
background: $color2;
|
||||||
padding: 4px 0;
|
padding: 4px 0;
|
||||||
|
@ -559,12 +563,12 @@ a.status__content__spoiler-link {
|
||||||
}
|
}
|
||||||
|
|
||||||
&.dropdown__left {
|
&.dropdown__left {
|
||||||
ul {
|
& > ul {
|
||||||
left: -98px;
|
left: -98px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
& > ul > li > a {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -1254,3 +1258,164 @@ button.active i.fa-retweet {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
background: radial-gradient(ellipse, rgba($color4, 0.23) 0%, rgba($color4, 0) 60%);
|
background: radial-gradient(ellipse, rgba($color4, 0.23) 0%, rgba($color4, 0) 60%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.emoji-dialog {
|
||||||
|
width: 280px;
|
||||||
|
height: 220px;
|
||||||
|
background: $color2;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 2px;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
box-shadow: 0 0 15px rgba($color8, 0.4);
|
||||||
|
|
||||||
|
.emojione {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-dialog-header {
|
||||||
|
padding: 0 10px;
|
||||||
|
background-color: $color3;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: inline-block;
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 42px;
|
||||||
|
padding: 9px 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
img, svg {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
filter: grayscale(100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background: lighten($color3, 6%);
|
||||||
|
|
||||||
|
img, svg {
|
||||||
|
filter: grayscale(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-row {
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow-y: hidden;
|
||||||
|
padding-left: 10px;
|
||||||
|
|
||||||
|
.emoji {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-category-header {
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow-y: hidden;
|
||||||
|
padding: 8px 16px 0;
|
||||||
|
display: table;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-category-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-weight: normal;
|
||||||
|
color: $color1;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-category-heading-decoration {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modifiers {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
vertical-align: middle;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-top: 4px;
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0 2px;
|
||||||
|
|
||||||
|
&:last-of-type {
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modifier {
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 10px;
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&.active:after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
width: 7px;
|
||||||
|
height: 7px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 2px solid $color1;
|
||||||
|
top: 2px;
|
||||||
|
left: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-search-wrapper {
|
||||||
|
padding: 6px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-search {
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 6px 4px;
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-categories-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
top: 42px;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-search-wrapper + .emoji-categories-wrapper {
|
||||||
|
top: 83px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-row .emoji:hover {
|
||||||
|
background: lighten($color2, 3%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
"css-loader": "^0.26.2",
|
"css-loader": "^0.26.2",
|
||||||
"dotenv": "^4.0.0",
|
"dotenv": "^4.0.0",
|
||||||
"emojione": "latest",
|
"emojione": "latest",
|
||||||
|
"emojione-picker": "^2.0.1",
|
||||||
"enzyme": "^2.7.1",
|
"enzyme": "^2.7.1",
|
||||||
"es6-promise": "^3.2.1",
|
"es6-promise": "^3.2.1",
|
||||||
"escape-html": "^1.0.3",
|
"escape-html": "^1.0.3",
|
||||||
|
@ -40,6 +41,7 @@
|
||||||
"react": "^15.4.2",
|
"react": "^15.4.2",
|
||||||
"react-addons-perf": "^15.4.2",
|
"react-addons-perf": "^15.4.2",
|
||||||
"react-addons-pure-render-mixin": "^15.4.2",
|
"react-addons-pure-render-mixin": "^15.4.2",
|
||||||
|
"react-addons-shallow-compare": "^15.4.2",
|
||||||
"react-addons-test-utils": "^15.4.2",
|
"react-addons-test-utils": "^15.4.2",
|
||||||
"react-autosuggest": "^7.0.1",
|
"react-autosuggest": "^7.0.1",
|
||||||
"react-decoration": "^1.4.0",
|
"react-decoration": "^1.4.0",
|
||||||
|
|
44
yarn.lock
44
yarn.lock
|
@ -2204,7 +2204,7 @@ doctrine@^2.0.0:
|
||||||
esutils "^2.0.2"
|
esutils "^2.0.2"
|
||||||
isarray "^1.0.0"
|
isarray "^1.0.0"
|
||||||
|
|
||||||
dom-helpers@^2.4.0:
|
dom-helpers@^2.4.0, "dom-helpers@^2.4.0 || ^3.0.0":
|
||||||
version "2.4.0"
|
version "2.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-2.4.0.tgz#9bb4b245f637367b1fa670274272aa28fe06c367"
|
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-2.4.0.tgz#9bb4b245f637367b1fa670274272aa28fe06c367"
|
||||||
|
|
||||||
|
@ -2287,7 +2287,17 @@ elliptic@^6.0.0:
|
||||||
hash.js "^1.0.0"
|
hash.js "^1.0.0"
|
||||||
inherits "^2.0.1"
|
inherits "^2.0.1"
|
||||||
|
|
||||||
emojione@latest:
|
emojione-picker@^2.0.1:
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/emojione-picker/-/emojione-picker-2.0.1.tgz#62e58db67d37a400a883c82d39abb1cc1c8ed65a"
|
||||||
|
dependencies:
|
||||||
|
emojione "^2.2.6"
|
||||||
|
escape-string-regexp "^1.0.5"
|
||||||
|
lodash "^4.15.0"
|
||||||
|
react-virtualized "^8.11.4"
|
||||||
|
store "^1.3.20"
|
||||||
|
|
||||||
|
emojione@^2.2.6, emojione@latest:
|
||||||
version "2.2.7"
|
version "2.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/emojione/-/emojione-2.2.7.tgz#46457cf6b9b2f8da13ae8a2e4e547de06ee15e96"
|
resolved "https://registry.yarnpkg.com/emojione/-/emojione-2.2.7.tgz#46457cf6b9b2f8da13ae8a2e4e547de06ee15e96"
|
||||||
|
|
||||||
|
@ -2413,7 +2423,7 @@ escape-html@^1.0.3, escape-html@~1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
||||||
|
|
||||||
escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2:
|
escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||||
|
|
||||||
|
@ -3628,7 +3638,7 @@ lodash.tail@^4.1.1:
|
||||||
version "4.1.1"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664"
|
resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664"
|
||||||
|
|
||||||
lodash@4.x.x, lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.1:
|
lodash@4.x.x, lodash@^4.0.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.1:
|
||||||
version "4.17.4"
|
version "4.17.4"
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
|
||||||
|
|
||||||
|
@ -3650,6 +3660,12 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
js-tokens "^1.0.1"
|
js-tokens "^1.0.1"
|
||||||
|
|
||||||
|
loose-envify@^1.3.0:
|
||||||
|
version "1.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
|
||||||
|
dependencies:
|
||||||
|
js-tokens "^3.0.0"
|
||||||
|
|
||||||
loud-rejection@^1.0.0:
|
loud-rejection@^1.0.0:
|
||||||
version "1.6.0"
|
version "1.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
|
resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
|
||||||
|
@ -4833,6 +4849,13 @@ react-addons-pure-render-mixin@>=0.14.0, react-addons-pure-render-mixin@^15.4.2:
|
||||||
fbjs "^0.8.4"
|
fbjs "^0.8.4"
|
||||||
object-assign "^4.1.0"
|
object-assign "^4.1.0"
|
||||||
|
|
||||||
|
react-addons-shallow-compare@^15.4.2:
|
||||||
|
version "15.4.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-addons-shallow-compare/-/react-addons-shallow-compare-15.4.2.tgz#027ffd9720e3a1e0b328dcd8fc62e214a0d174a5"
|
||||||
|
dependencies:
|
||||||
|
fbjs "^0.8.4"
|
||||||
|
object-assign "^4.1.0"
|
||||||
|
|
||||||
react-addons-test-utils@^15.4.2:
|
react-addons-test-utils@^15.4.2:
|
||||||
version "15.4.2"
|
version "15.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-addons-test-utils/-/react-addons-test-utils-15.4.2.tgz#93bcaa718fcae7360d42e8fb1c09756cc36302a2"
|
resolved "https://registry.yarnpkg.com/react-addons-test-utils/-/react-addons-test-utils-15.4.2.tgz#93bcaa718fcae7360d42e8fb1c09756cc36302a2"
|
||||||
|
@ -5051,6 +5074,15 @@ react-toggle@^2.1.1:
|
||||||
classnames "~2.2"
|
classnames "~2.2"
|
||||||
react-addons-pure-render-mixin ">=0.14.0"
|
react-addons-pure-render-mixin ">=0.14.0"
|
||||||
|
|
||||||
|
react-virtualized@^8.11.4:
|
||||||
|
version "8.11.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-8.11.4.tgz#0bb94f1ecbd286d07145ce63983d0a11724522c0"
|
||||||
|
dependencies:
|
||||||
|
babel-runtime "^6.11.6"
|
||||||
|
classnames "^2.2.3"
|
||||||
|
dom-helpers "^2.4.0 || ^3.0.0"
|
||||||
|
loose-envify "^1.3.0"
|
||||||
|
|
||||||
react@^15.4.2:
|
react@^15.4.2:
|
||||||
version "15.4.2"
|
version "15.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/react/-/react-15.4.2.tgz#41f7991b26185392ba9bae96c8889e7e018397ef"
|
resolved "https://registry.yarnpkg.com/react/-/react-15.4.2.tgz#41f7991b26185392ba9bae96c8889e7e018397ef"
|
||||||
|
@ -5623,6 +5655,10 @@ stdout-stream@^1.4.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
readable-stream "^2.0.1"
|
readable-stream "^2.0.1"
|
||||||
|
|
||||||
|
store@^1.3.20:
|
||||||
|
version "1.3.20"
|
||||||
|
resolved "https://registry.yarnpkg.com/store/-/store-1.3.20.tgz#13ea7e3fb2d6c239868265d686b1d84e99c5be3e"
|
||||||
|
|
||||||
stream-browserify@^2.0.0, stream-browserify@^2.0.1:
|
stream-browserify@^2.0.0, stream-browserify@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
|
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
|
||||||
|
|
Loading…
Reference in a new issue