Basic username autocomplete for text area
This commit is contained in:
parent
fa1cc2d05a
commit
c49f6290eb
8 changed files with 235 additions and 13 deletions
|
@ -13,6 +13,9 @@ export const COMPOSE_UPLOAD_FAIL = 'COMPOSE_UPLOAD_FAIL';
|
||||||
export const COMPOSE_UPLOAD_PROGRESS = 'COMPOSE_UPLOAD_PROGRESS';
|
export const COMPOSE_UPLOAD_PROGRESS = 'COMPOSE_UPLOAD_PROGRESS';
|
||||||
export const COMPOSE_UPLOAD_UNDO = 'COMPOSE_UPLOAD_UNDO';
|
export const COMPOSE_UPLOAD_UNDO = 'COMPOSE_UPLOAD_UNDO';
|
||||||
|
|
||||||
|
export const COMPOSE_SUGGESTIONS_CLEAR = 'COMPOSE_SUGGESTIONS_CLEAR';
|
||||||
|
export const COMPOSE_SUGGESTIONS_READY = 'COMPOSE_SUGGESTIONS_READY';
|
||||||
|
|
||||||
export function changeCompose(text) {
|
export function changeCompose(text) {
|
||||||
return {
|
return {
|
||||||
type: COMPOSE_CHANGE,
|
type: COMPOSE_CHANGE,
|
||||||
|
@ -129,3 +132,27 @@ export function undoUploadCompose(media_id) {
|
||||||
media_id: media_id
|
media_id: media_id
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function clearComposeSuggestions() {
|
||||||
|
return {
|
||||||
|
type: COMPOSE_SUGGESTIONS_CLEAR
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export function fetchComposeSuggestions(token) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
const loadedCandidates = getState().get('accounts').filter(item => item.get('acct').toLowerCase().slice(0, token.length) === token).map(item => ({
|
||||||
|
label: item.get('acct'),
|
||||||
|
completion: item.get('acct').slice(0, token.length)
|
||||||
|
})).toList().toJS();
|
||||||
|
|
||||||
|
dispatch(readyComposeSuggestions(loadedCandidates));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export function readyComposeSuggestions(accounts) {
|
||||||
|
return {
|
||||||
|
type: COMPOSE_SUGGESTIONS_READY,
|
||||||
|
accounts
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -4,11 +4,62 @@ import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import ReplyIndicator from './reply_indicator';
|
import ReplyIndicator from './reply_indicator';
|
||||||
import UploadButton from './upload_button';
|
import UploadButton from './upload_button';
|
||||||
|
import Autosuggest from 'react-autosuggest';
|
||||||
|
|
||||||
|
const getTokenForSuggestions = (str, caretPosition) => {
|
||||||
|
let word;
|
||||||
|
|
||||||
|
let left = str.slice(0, caretPosition).search(/\S+$/);
|
||||||
|
let right = str.slice(caretPosition).search(/\s/);
|
||||||
|
|
||||||
|
if (right < 0) {
|
||||||
|
word = str.slice(left);
|
||||||
|
} else {
|
||||||
|
word = str.slice(left, right + caretPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!word || word.trim().length < 2 || word[0] !== '@') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
word = word.trim().toLowerCase().slice(1);
|
||||||
|
|
||||||
|
if (word.length > 0) {
|
||||||
|
return word;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSuggestionValue = suggestion => suggestion;
|
||||||
|
|
||||||
|
const renderSuggestion = suggestion => (
|
||||||
|
<span>{suggestion}</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
const textareaStyle = {
|
||||||
|
display: 'block',
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
width: '100%',
|
||||||
|
height: '100px',
|
||||||
|
resize: 'none',
|
||||||
|
border: 'none',
|
||||||
|
color: '#282c37',
|
||||||
|
padding: '10px',
|
||||||
|
fontFamily: 'Roboto',
|
||||||
|
fontSize: '14px',
|
||||||
|
margin: '0'
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderInputComponent = inputProps => (
|
||||||
|
<textarea {...inputProps} placeholder='What is on your mind?' className='compose-form__textarea' style={textareaStyle} />
|
||||||
|
);
|
||||||
|
|
||||||
const ComposeForm = React.createClass({
|
const ComposeForm = React.createClass({
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
text: React.PropTypes.string.isRequired,
|
text: React.PropTypes.string.isRequired,
|
||||||
|
suggestions: React.PropTypes.array,
|
||||||
is_submitting: React.PropTypes.bool,
|
is_submitting: React.PropTypes.bool,
|
||||||
is_uploading: React.PropTypes.bool,
|
is_uploading: React.PropTypes.bool,
|
||||||
in_reply_to: ImmutablePropTypes.map,
|
in_reply_to: ImmutablePropTypes.map,
|
||||||
|
@ -35,7 +86,39 @@ const ComposeForm = React.createClass({
|
||||||
|
|
||||||
componentDidUpdate (prevProps) {
|
componentDidUpdate (prevProps) {
|
||||||
if (prevProps.text !== this.props.text || prevProps.in_reply_to !== this.props.in_reply_to) {
|
if (prevProps.text !== this.props.text || prevProps.in_reply_to !== this.props.in_reply_to) {
|
||||||
this.refs.textarea.focus();
|
const node = ReactDOM.findDOMNode(this.refs.autosuggest);
|
||||||
|
const textarea = node.querySelector('textarea');
|
||||||
|
|
||||||
|
if (textarea) {
|
||||||
|
textarea.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onSuggestionsClearRequested () {
|
||||||
|
this.props.onClearSuggestions();
|
||||||
|
},
|
||||||
|
|
||||||
|
onSuggestionsFetchRequested ({ value }) {
|
||||||
|
const node = ReactDOM.findDOMNode(this.refs.autosuggest);
|
||||||
|
const textarea = node.querySelector('textarea');
|
||||||
|
|
||||||
|
if (textarea) {
|
||||||
|
const token = getTokenForSuggestions(value, textarea.selectionStart);
|
||||||
|
|
||||||
|
if (token !== null) {
|
||||||
|
this.props.onFetchSuggestions(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onSuggestionSelected (e, { suggestionValue, method }) {
|
||||||
|
const node = ReactDOM.findDOMNode(this.refs.autosuggest);
|
||||||
|
const textarea = node.querySelector('textarea');
|
||||||
|
|
||||||
|
if (textarea) {
|
||||||
|
const str = this.props.text;
|
||||||
|
this.props.onChange([str.slice(0, textarea.selectionStart), suggestionValue, str.slice(textarea.selectionStart)].join(''));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -47,11 +130,29 @@ const ComposeForm = React.createClass({
|
||||||
replyArea = <ReplyIndicator status={this.props.in_reply_to} onCancel={this.props.onCancelReply} />;
|
replyArea = <ReplyIndicator status={this.props.in_reply_to} onCancel={this.props.onCancelReply} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const inputProps = {
|
||||||
|
placeholder: 'What is on your mind?',
|
||||||
|
value: this.props.text,
|
||||||
|
onKeyUp: this.handleKeyUp,
|
||||||
|
onChange: this.handleChange,
|
||||||
|
disabled: disabled
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: '10px' }}>
|
<div style={{ padding: '10px' }}>
|
||||||
{replyArea}
|
{replyArea}
|
||||||
|
|
||||||
<textarea ref='textarea' disabled={disabled} placeholder='What is on your mind?' value={this.props.text} onKeyUp={this.handleKeyUp} onChange={this.handleChange} className='compose-form__textarea' style={{ display: 'block', boxSizing: 'border-box', width: '100%', height: '100px', resize: 'none', border: 'none', color: '#282c37', padding: '10px', fontFamily: 'Roboto', fontSize: '14px', margin: '0' }} />
|
<Autosuggest
|
||||||
|
ref='autosuggest'
|
||||||
|
suggestions={this.props.suggestions}
|
||||||
|
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
|
||||||
|
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
|
||||||
|
onSuggestionSelected={this.onSuggestionSelected}
|
||||||
|
getSuggestionValue={getSuggestionValue}
|
||||||
|
renderSuggestion={renderSuggestion}
|
||||||
|
renderInputComponent={renderInputComponent}
|
||||||
|
inputProps={inputProps}
|
||||||
|
/>
|
||||||
|
|
||||||
<div style={{ marginTop: '10px', overflow: 'hidden' }}>
|
<div style={{ marginTop: '10px', overflow: 'hidden' }}>
|
||||||
<div style={{ float: 'right' }}><Button text='Publish' onClick={this.handleSubmit} disabled={disabled} /></div>
|
<div style={{ float: 'right' }}><Button text='Publish' onClick={this.handleSubmit} disabled={disabled} /></div>
|
||||||
|
|
|
@ -24,7 +24,7 @@ const UploadButton = React.createClass({
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Button disabled={this.props.disabled} onClick={this.handleClick} block={true}>
|
<Button disabled={this.props.disabled} onClick={this.handleClick} block={true}>
|
||||||
<i className='fa fa-fw fa-photo' /> Add images
|
<i className='fa fa-fw fa-photo' /> Add media
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<input ref='fileElement' type='file' multiple={false} onChange={this.handleChange} disabled={this.props.disabled} style={{ display: 'none' }} />
|
<input ref='fileElement' type='file' multiple={false} onChange={this.handleChange} disabled={this.props.disabled} style={{ display: 'none' }} />
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import ComposeForm from '../components/compose_form';
|
import ComposeForm from '../components/compose_form';
|
||||||
import { changeCompose, submitCompose, cancelReplyCompose } from '../../../actions/compose';
|
import {
|
||||||
import { makeGetStatus } from '../../../selectors';
|
changeCompose,
|
||||||
|
submitCompose,
|
||||||
|
cancelReplyCompose,
|
||||||
|
clearComposeSuggestions,
|
||||||
|
fetchComposeSuggestions
|
||||||
|
} from '../../../actions/compose';
|
||||||
|
import { makeGetStatus } from '../../../selectors';
|
||||||
|
|
||||||
const makeMapStateToProps = () => {
|
const makeMapStateToProps = () => {
|
||||||
const getStatus = makeGetStatus();
|
const getStatus = makeGetStatus();
|
||||||
|
@ -9,6 +15,7 @@ const makeMapStateToProps = () => {
|
||||||
const mapStateToProps = function (state, props) {
|
const mapStateToProps = function (state, props) {
|
||||||
return {
|
return {
|
||||||
text: state.getIn(['compose', 'text']),
|
text: state.getIn(['compose', 'text']),
|
||||||
|
suggestions: state.getIn(['compose', 'suggestions']),
|
||||||
is_submitting: state.getIn(['compose', 'is_submitting']),
|
is_submitting: state.getIn(['compose', 'is_submitting']),
|
||||||
is_uploading: state.getIn(['compose', 'is_uploading']),
|
is_uploading: state.getIn(['compose', 'is_uploading']),
|
||||||
in_reply_to: getStatus(state, state.getIn(['compose', 'in_reply_to']))
|
in_reply_to: getStatus(state, state.getIn(['compose', 'in_reply_to']))
|
||||||
|
@ -20,16 +27,24 @@ const makeMapStateToProps = () => {
|
||||||
|
|
||||||
const mapDispatchToProps = function (dispatch) {
|
const mapDispatchToProps = function (dispatch) {
|
||||||
return {
|
return {
|
||||||
onChange: function (text) {
|
onChange (text) {
|
||||||
dispatch(changeCompose(text));
|
dispatch(changeCompose(text));
|
||||||
},
|
},
|
||||||
|
|
||||||
onSubmit: function () {
|
onSubmit () {
|
||||||
dispatch(submitCompose());
|
dispatch(submitCompose());
|
||||||
},
|
},
|
||||||
|
|
||||||
onCancelReply: function () {
|
onCancelReply () {
|
||||||
dispatch(cancelReplyCompose());
|
dispatch(cancelReplyCompose());
|
||||||
|
},
|
||||||
|
|
||||||
|
onClearSuggestions () {
|
||||||
|
dispatch(clearComposeSuggestions());
|
||||||
|
},
|
||||||
|
|
||||||
|
onFetchSuggestions (token) {
|
||||||
|
dispatch(fetchComposeSuggestions(token));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,9 @@ import {
|
||||||
COMPOSE_UPLOAD_SUCCESS,
|
COMPOSE_UPLOAD_SUCCESS,
|
||||||
COMPOSE_UPLOAD_FAIL,
|
COMPOSE_UPLOAD_FAIL,
|
||||||
COMPOSE_UPLOAD_UNDO,
|
COMPOSE_UPLOAD_UNDO,
|
||||||
COMPOSE_UPLOAD_PROGRESS
|
COMPOSE_UPLOAD_PROGRESS,
|
||||||
|
COMPOSE_SUGGESTIONS_CLEAR,
|
||||||
|
COMPOSE_SUGGESTIONS_READY
|
||||||
} from '../actions/compose';
|
} from '../actions/compose';
|
||||||
import { TIMELINE_DELETE } from '../actions/timelines';
|
import { TIMELINE_DELETE } from '../actions/timelines';
|
||||||
import { ACCOUNT_SET_SELF } from '../actions/accounts';
|
import { ACCOUNT_SET_SELF } from '../actions/accounts';
|
||||||
|
@ -22,7 +24,8 @@ const initialState = Immutable.Map({
|
||||||
is_submitting: false,
|
is_submitting: false,
|
||||||
is_uploading: false,
|
is_uploading: false,
|
||||||
progress: 0,
|
progress: 0,
|
||||||
media_attachments: Immutable.List([]),
|
media_attachments: Immutable.List(),
|
||||||
|
suggestions: [],
|
||||||
me: null
|
me: null
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -95,6 +98,10 @@ export default function compose(state = initialState, action) {
|
||||||
return state.set('progress', Math.round((action.loaded / action.total) * 100));
|
return state.set('progress', Math.round((action.loaded / action.total) * 100));
|
||||||
case COMPOSE_MENTION:
|
case COMPOSE_MENTION:
|
||||||
return state.update('text', text => `${text}@${action.account.get('acct')} `);
|
return state.update('text', text => `${text}@${action.account.get('acct')} `);
|
||||||
|
case COMPOSE_SUGGESTIONS_CLEAR:
|
||||||
|
return state.set('suggestions', []);
|
||||||
|
case COMPOSE_SUGGESTIONS_READY:
|
||||||
|
return state.set('suggestions', action.accounts);
|
||||||
case TIMELINE_DELETE:
|
case TIMELINE_DELETE:
|
||||||
if (action.id === state.get('in_reply_to')) {
|
if (action.id === state.get('in_reply_to')) {
|
||||||
return state.set('in_reply_to', null);
|
return state.set('in_reply_to', null);
|
||||||
|
|
|
@ -266,3 +266,31 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.react-autosuggest__container {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-autosuggest__suggestions-container {
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 99;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-autosuggest__suggestions-list {
|
||||||
|
background: #9baec8;
|
||||||
|
color: #282c37;
|
||||||
|
box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-autosuggest__suggestion {
|
||||||
|
padding: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-autosuggest__suggestion--focused {
|
||||||
|
background: #2b90d9;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
"sinon": "^1.17.6"
|
"sinon": "^1.17.6"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"react-autosuggest": "^7.0.1",
|
||||||
"react-responsive": "^1.1.5",
|
"react-responsive": "^1.1.5",
|
||||||
"react-router-scroll": "^0.3.2",
|
"react-router-scroll": "^0.3.2",
|
||||||
"react-skylight": "^0.4.1"
|
"react-skylight": "^0.4.1"
|
||||||
|
|
45
yarn.lock
45
yarn.lock
|
@ -3243,6 +3243,10 @@ oauth-sign@~0.8.1:
|
||||||
version "0.8.2"
|
version "0.8.2"
|
||||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
|
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
|
||||||
|
|
||||||
|
object-assign@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2"
|
||||||
|
|
||||||
object-assign@^4.0.0, object-assign@^4.0.1, object-assign@^4.1.0:
|
object-assign@^4.0.0, object-assign@^4.0.1, object-assign@^4.1.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0"
|
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0"
|
||||||
|
@ -3807,6 +3811,22 @@ react-addons-pure-render-mixin@^15.3.1:
|
||||||
version "15.3.2"
|
version "15.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-addons-test-utils/-/react-addons-test-utils-15.3.2.tgz#c09a44f583425a4a9c1b38444d7a6c3e6f0f41f6"
|
resolved "https://registry.yarnpkg.com/react-addons-test-utils/-/react-addons-test-utils-15.3.2.tgz#c09a44f583425a4a9c1b38444d7a6c3e6f0f41f6"
|
||||||
|
|
||||||
|
react-autosuggest:
|
||||||
|
version "7.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-autosuggest/-/react-autosuggest-7.0.1.tgz#e751d2c2e516a344f6cdc150672e85f134f5f2f1"
|
||||||
|
dependencies:
|
||||||
|
react-autowhatever "^7.0.0"
|
||||||
|
react-redux "^4.4.5"
|
||||||
|
redux "^3.6.0"
|
||||||
|
shallow-equal "^1.0.0"
|
||||||
|
|
||||||
|
react-autowhatever@^7.0.0:
|
||||||
|
version "7.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-autowhatever/-/react-autowhatever-7.0.0.tgz#7ea19f8024183acf1568fc8e4b76c0d0cc250d00"
|
||||||
|
dependencies:
|
||||||
|
react-themeable "^1.1.0"
|
||||||
|
section-iterator "^2.0.0"
|
||||||
|
|
||||||
react-deep-force-update@^1.0.0:
|
react-deep-force-update@^1.0.0:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-deep-force-update/-/react-deep-force-update-1.0.1.tgz#f911b5be1d2a6fe387507dd6e9a767aa2924b4c7"
|
resolved "https://registry.yarnpkg.com/react-deep-force-update/-/react-deep-force-update-1.0.1.tgz#f911b5be1d2a6fe387507dd6e9a767aa2924b4c7"
|
||||||
|
@ -3878,6 +3898,15 @@ react-redux-loading-bar@^2.3.3:
|
||||||
version "2.4.0"
|
version "2.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-redux-loading-bar/-/react-redux-loading-bar-2.4.0.tgz#00cd884c7ea8e0146fb94aeb1435b1a0caffd888"
|
resolved "https://registry.yarnpkg.com/react-redux-loading-bar/-/react-redux-loading-bar-2.4.0.tgz#00cd884c7ea8e0146fb94aeb1435b1a0caffd888"
|
||||||
|
|
||||||
|
react-redux@^4.4.5:
|
||||||
|
version "4.4.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-4.4.5.tgz#f509a2981be2252d10c629ef7c559347a4aec457"
|
||||||
|
dependencies:
|
||||||
|
hoist-non-react-statics "^1.0.3"
|
||||||
|
invariant "^2.0.0"
|
||||||
|
lodash "^4.2.0"
|
||||||
|
loose-envify "^1.1.0"
|
||||||
|
|
||||||
react-redux@^5.0.0-beta.3:
|
react-redux@^5.0.0-beta.3:
|
||||||
version "5.0.0-beta.3"
|
version "5.0.0-beta.3"
|
||||||
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.0-beta.3.tgz#d50bfb00799cf7d2a9fd55fe34d6b3ecc24d3072"
|
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.0-beta.3.tgz#d50bfb00799cf7d2a9fd55fe34d6b3ecc24d3072"
|
||||||
|
@ -3931,6 +3960,12 @@ react-skylight:
|
||||||
version "0.4.1"
|
version "0.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-skylight/-/react-skylight-0.4.1.tgz#07d1af6dea0a50a5d8122a786a8ce8bc6bdf2241"
|
resolved "https://registry.yarnpkg.com/react-skylight/-/react-skylight-0.4.1.tgz#07d1af6dea0a50a5d8122a786a8ce8bc6bdf2241"
|
||||||
|
|
||||||
|
react-themeable@^1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-themeable/-/react-themeable-1.1.0.tgz#7d4466dd9b2b5fa75058727825e9f152ba379a0e"
|
||||||
|
dependencies:
|
||||||
|
object-assign "^3.0.0"
|
||||||
|
|
||||||
react@^15.3.2:
|
react@^15.3.2:
|
||||||
version "15.3.2"
|
version "15.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/react/-/react-15.3.2.tgz#a7bccd2fee8af126b0317e222c28d1d54528d09e"
|
resolved "https://registry.yarnpkg.com/react/-/react-15.3.2.tgz#a7bccd2fee8af126b0317e222c28d1d54528d09e"
|
||||||
|
@ -4033,7 +4068,7 @@ redux-thunk@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.1.0.tgz#c724bfee75dbe352da2e3ba9bc14302badd89a98"
|
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.1.0.tgz#c724bfee75dbe352da2e3ba9bc14302badd89a98"
|
||||||
|
|
||||||
redux@^3.5.2:
|
redux@^3.5.2, redux@^3.6.0:
|
||||||
version "3.6.0"
|
version "3.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/redux/-/redux-3.6.0.tgz#887c2b3d0b9bd86eca2be70571c27654c19e188d"
|
resolved "https://registry.yarnpkg.com/redux/-/redux-3.6.0.tgz#887c2b3d0b9bd86eca2be70571c27654c19e188d"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -4170,6 +4205,10 @@ scroll-behavior@^0.8.0:
|
||||||
dom-helpers "^2.4.0"
|
dom-helpers "^2.4.0"
|
||||||
invariant "^2.2.1"
|
invariant "^2.2.1"
|
||||||
|
|
||||||
|
section-iterator@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/section-iterator/-/section-iterator-2.0.0.tgz#bf444d7afeeb94ad43c39ad2fb26151627ccba2a"
|
||||||
|
|
||||||
semver@~5.3.0:
|
semver@~5.3.0:
|
||||||
version "5.3.0"
|
version "5.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
|
||||||
|
@ -4232,6 +4271,10 @@ sha.js@2.2.6:
|
||||||
version "2.2.6"
|
version "2.2.6"
|
||||||
resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.2.6.tgz#17ddeddc5f722fb66501658895461977867315ba"
|
resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.2.6.tgz#17ddeddc5f722fb66501658895461977867315ba"
|
||||||
|
|
||||||
|
shallow-equal@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-1.0.0.tgz#508d1838b3de590ab8757b011b25e430900945f7"
|
||||||
|
|
||||||
shallowequal@0.2.x:
|
shallowequal@0.2.x:
|
||||||
version "0.2.2"
|
version "0.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-0.2.2.tgz#1e32fd5bcab6ad688a4812cb0cc04efc75c7014e"
|
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-0.2.2.tgz#1e32fd5bcab6ad688a4812cb0cc04efc75c7014e"
|
||||||
|
|
Loading…
Reference in a new issue