Merge pull request #386 from mitchhentges/file-drop-ui
On file-drag, show a border around textareapull/389/head
commit
e6657d7342
|
@ -32,6 +32,7 @@ const AutosuggestTextarea = React.createClass({
|
|||
value: React.PropTypes.string,
|
||||
suggestions: ImmutablePropTypes.list,
|
||||
disabled: React.PropTypes.bool,
|
||||
fileDropDate: React.PropTypes.instanceOf(Date),
|
||||
placeholder: React.PropTypes.string,
|
||||
onSuggestionSelected: React.PropTypes.func.isRequired,
|
||||
onSuggestionsClearRequested: React.PropTypes.func.isRequired,
|
||||
|
@ -42,6 +43,8 @@ const AutosuggestTextarea = React.createClass({
|
|||
|
||||
getInitialState () {
|
||||
return {
|
||||
isFileDragging: false,
|
||||
fileDraggingDate: undefined,
|
||||
suggestionsHidden: false,
|
||||
selectedSuggestion: 0,
|
||||
lastToken: null,
|
||||
|
@ -120,21 +123,51 @@ const AutosuggestTextarea = React.createClass({
|
|||
if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden) {
|
||||
this.setState({ suggestionsHidden: false });
|
||||
}
|
||||
|
||||
const fileDropDate = nextProps.fileDropDate;
|
||||
const { isFileDragging, fileDraggingDate } = this.state;
|
||||
|
||||
/*
|
||||
* We can't detect drop events, because they might not be on the textarea (the app allows dropping anywhere in the
|
||||
* window). Instead, on-drop, we notify this textarea to stop its hover effect by passing in a prop with the
|
||||
* drop-date.
|
||||
*/
|
||||
if (isFileDragging && fileDraggingDate && fileDropDate // if dragging when props updated, and dates aren't undefined
|
||||
&& fileDropDate > fileDraggingDate) { // and if the drop date is now greater than when we started dragging
|
||||
// then we should stop dragging
|
||||
this.setState({
|
||||
isFileDragging: false
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
setTextarea (c) {
|
||||
this.textarea = c;
|
||||
},
|
||||
|
||||
onDragEnter () {
|
||||
this.setState({
|
||||
isFileDragging: true,
|
||||
fileDraggingDate: new Date()
|
||||
})
|
||||
},
|
||||
|
||||
onDragExit () {
|
||||
this.setState({
|
||||
isFileDragging: false
|
||||
})
|
||||
},
|
||||
|
||||
render () {
|
||||
const { value, suggestions, disabled, placeholder, onKeyUp } = this.props;
|
||||
const { suggestionsHidden, selectedSuggestion } = this.state;
|
||||
const { value, suggestions, fileDropDate, disabled, placeholder, onKeyUp } = this.props;
|
||||
const { isFileDragging, suggestionsHidden, selectedSuggestion } = this.state;
|
||||
const className = isFileDragging ? 'autosuggest-textarea__textarea file-drop' : 'autosuggest-textarea__textarea';
|
||||
|
||||
return (
|
||||
<div className='autosuggest-textarea'>
|
||||
<textarea
|
||||
ref={this.setTextarea}
|
||||
className='autosuggest-textarea__textarea'
|
||||
className={className}
|
||||
disabled={disabled}
|
||||
placeholder={placeholder}
|
||||
value={value}
|
||||
|
@ -142,6 +175,8 @@ const AutosuggestTextarea = React.createClass({
|
|||
onKeyDown={this.onKeyDown}
|
||||
onKeyUp={onKeyUp}
|
||||
onBlur={this.onBlur}
|
||||
onDragEnter={this.onDragEnter}
|
||||
onDragExit={this.onDragExit}
|
||||
/>
|
||||
|
||||
<div style={{ display: (suggestions.size > 0 && !suggestionsHidden) ? 'block' : 'none' }} className='autosuggest-textarea__suggestions'>
|
||||
|
|
|
@ -27,6 +27,7 @@ const ComposeForm = React.createClass({
|
|||
sensitive: React.PropTypes.bool,
|
||||
unlisted: React.PropTypes.bool,
|
||||
private: React.PropTypes.bool,
|
||||
fileDropDate: React.PropTypes.instanceOf(Date),
|
||||
is_submitting: React.PropTypes.bool,
|
||||
is_uploading: React.PropTypes.bool,
|
||||
in_reply_to: ImmutablePropTypes.map,
|
||||
|
@ -110,6 +111,7 @@ const ComposeForm = React.createClass({
|
|||
ref={this.setAutosuggestTextarea}
|
||||
placeholder={intl.formatMessage(messages.placeholder)}
|
||||
disabled={disabled}
|
||||
fileDropDate={this.props.fileDropDate}
|
||||
value={this.props.text}
|
||||
onChange={this.handleChange}
|
||||
suggestions={this.props.suggestions}
|
||||
|
|
|
@ -24,6 +24,7 @@ const makeMapStateToProps = () => {
|
|||
sensitive: state.getIn(['compose', 'sensitive']),
|
||||
unlisted: state.getIn(['compose', 'unlisted']),
|
||||
private: state.getIn(['compose', 'private']),
|
||||
fileDropDate: state.getIn(['compose', 'fileDropDate']),
|
||||
is_submitting: state.getIn(['compose', 'is_submitting']),
|
||||
is_uploading: state.getIn(['compose', 'is_uploading']),
|
||||
in_reply_to: getStatus(state, state.getIn(['compose', 'in_reply_to'])),
|
||||
|
|
|
@ -30,6 +30,7 @@ const initialState = Immutable.Map({
|
|||
unlisted: false,
|
||||
private: false,
|
||||
text: '',
|
||||
fileDropDate: null,
|
||||
in_reply_to: null,
|
||||
is_submitting: false,
|
||||
is_uploading: false,
|
||||
|
@ -116,7 +117,10 @@ export default function compose(state = initialState, action) {
|
|||
case COMPOSE_SUBMIT_FAIL:
|
||||
return state.set('is_submitting', false);
|
||||
case COMPOSE_UPLOAD_REQUEST:
|
||||
return state.set('is_uploading', true);
|
||||
return state.withMutations(map => {
|
||||
map.set('is_uploading', true);
|
||||
map.set('fileDropDate', new Date());
|
||||
});
|
||||
case COMPOSE_UPLOAD_SUCCESS:
|
||||
return appendMedia(state, Immutable.fromJS(action.media));
|
||||
case COMPOSE_UPLOAD_FAIL:
|
||||
|
|
|
@ -549,13 +549,19 @@
|
|||
width: 100%;
|
||||
height: 100px;
|
||||
resize: none;
|
||||
border: none;
|
||||
color: #282c37;
|
||||
padding: 10px;
|
||||
padding: 7px;
|
||||
font-family: 'Roboto';
|
||||
font-size: 14px;
|
||||
margin: 0;
|
||||
resize: vertical;
|
||||
|
||||
border: 3px dashed transparent;
|
||||
transition: border-color 0.3s ease;
|
||||
|
||||
&.file-drop {
|
||||
border-color: #aaa;
|
||||
}
|
||||
}
|
||||
|
||||
.autosuggest-textarea__suggestions {
|
||||
|
|
Loading…
Reference in New Issue