On file-drag, show a border around textarea

This commit is contained in:
Mitchell Hentges 2017-01-03 00:36:48 -08:00
parent 3125dd8920
commit 4d300e2507
5 changed files with 54 additions and 6 deletions

View file

@ -32,6 +32,7 @@ const AutosuggestTextarea = React.createClass({
value: React.PropTypes.string, value: React.PropTypes.string,
suggestions: ImmutablePropTypes.list, suggestions: ImmutablePropTypes.list,
disabled: React.PropTypes.bool, disabled: React.PropTypes.bool,
fileDropDate: React.PropTypes.instanceOf(Date),
placeholder: React.PropTypes.string, placeholder: React.PropTypes.string,
onSuggestionSelected: React.PropTypes.func.isRequired, onSuggestionSelected: React.PropTypes.func.isRequired,
onSuggestionsClearRequested: React.PropTypes.func.isRequired, onSuggestionsClearRequested: React.PropTypes.func.isRequired,
@ -42,6 +43,8 @@ const AutosuggestTextarea = React.createClass({
getInitialState () { getInitialState () {
return { return {
isFileDragging: false,
fileDraggingDate: undefined,
suggestionsHidden: false, suggestionsHidden: false,
selectedSuggestion: 0, selectedSuggestion: 0,
lastToken: null, lastToken: null,
@ -120,21 +123,51 @@ const AutosuggestTextarea = React.createClass({
if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden) { if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden) {
this.setState({ suggestionsHidden: false }); 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) { setTextarea (c) {
this.textarea = c; this.textarea = c;
}, },
onDragEnter () {
this.setState({
isFileDragging: true,
fileDraggingDate: new Date()
})
},
onDragExit () {
this.setState({
isFileDragging: false
})
},
render () { render () {
const { value, suggestions, disabled, placeholder, onKeyUp } = this.props; const { value, suggestions, fileDropDate, disabled, placeholder, onKeyUp } = this.props;
const { suggestionsHidden, selectedSuggestion } = this.state; const { isFileDragging, suggestionsHidden, selectedSuggestion } = this.state;
const className = isFileDragging ? 'autosuggest-textarea__textarea file-drop' : 'autosuggest-textarea__textarea';
return ( return (
<div className='autosuggest-textarea'> <div className='autosuggest-textarea'>
<textarea <textarea
ref={this.setTextarea} ref={this.setTextarea}
className='autosuggest-textarea__textarea' className={className}
disabled={disabled} disabled={disabled}
placeholder={placeholder} placeholder={placeholder}
value={value} value={value}
@ -142,6 +175,8 @@ const AutosuggestTextarea = React.createClass({
onKeyDown={this.onKeyDown} onKeyDown={this.onKeyDown}
onKeyUp={onKeyUp} onKeyUp={onKeyUp}
onBlur={this.onBlur} onBlur={this.onBlur}
onDragEnter={this.onDragEnter}
onDragExit={this.onDragExit}
/> />
<div style={{ display: (suggestions.size > 0 && !suggestionsHidden) ? 'block' : 'none' }} className='autosuggest-textarea__suggestions'> <div style={{ display: (suggestions.size > 0 && !suggestionsHidden) ? 'block' : 'none' }} className='autosuggest-textarea__suggestions'>

View file

@ -27,6 +27,7 @@ const ComposeForm = React.createClass({
sensitive: React.PropTypes.bool, sensitive: React.PropTypes.bool,
unlisted: React.PropTypes.bool, unlisted: React.PropTypes.bool,
private: React.PropTypes.bool, private: React.PropTypes.bool,
fileDropDate: React.PropTypes.instanceOf(Date),
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,
@ -110,6 +111,7 @@ const ComposeForm = React.createClass({
ref={this.setAutosuggestTextarea} ref={this.setAutosuggestTextarea}
placeholder={intl.formatMessage(messages.placeholder)} placeholder={intl.formatMessage(messages.placeholder)}
disabled={disabled} disabled={disabled}
fileDropDate={this.props.fileDropDate}
value={this.props.text} value={this.props.text}
onChange={this.handleChange} onChange={this.handleChange}
suggestions={this.props.suggestions} suggestions={this.props.suggestions}

View file

@ -24,6 +24,7 @@ const makeMapStateToProps = () => {
sensitive: state.getIn(['compose', 'sensitive']), sensitive: state.getIn(['compose', 'sensitive']),
unlisted: state.getIn(['compose', 'unlisted']), unlisted: state.getIn(['compose', 'unlisted']),
private: state.getIn(['compose', 'private']), private: state.getIn(['compose', 'private']),
fileDropDate: state.getIn(['compose', 'fileDropDate']),
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'])),

View file

@ -30,6 +30,7 @@ const initialState = Immutable.Map({
unlisted: false, unlisted: false,
private: false, private: false,
text: '', text: '',
fileDropDate: null,
in_reply_to: null, in_reply_to: null,
is_submitting: false, is_submitting: false,
is_uploading: false, is_uploading: false,
@ -116,7 +117,10 @@ export default function compose(state = initialState, action) {
case COMPOSE_SUBMIT_FAIL: case COMPOSE_SUBMIT_FAIL:
return state.set('is_submitting', false); return state.set('is_submitting', false);
case COMPOSE_UPLOAD_REQUEST: 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: case COMPOSE_UPLOAD_SUCCESS:
return appendMedia(state, Immutable.fromJS(action.media)); return appendMedia(state, Immutable.fromJS(action.media));
case COMPOSE_UPLOAD_FAIL: case COMPOSE_UPLOAD_FAIL:

View file

@ -549,13 +549,19 @@
width: 100%; width: 100%;
height: 100px; height: 100px;
resize: none; resize: none;
border: none;
color: #282c37; color: #282c37;
padding: 10px; padding: 7px;
font-family: 'Roboto'; font-family: 'Roboto';
font-size: 14px; font-size: 14px;
margin: 0; margin: 0;
resize: vertical; resize: vertical;
border: 3px dashed transparent;
transition: border-color 0.3s ease;
&.file-drop {
border-color: #aaa;
}
} }
.autosuggest-textarea__suggestions { .autosuggest-textarea__suggestions {