forked from cybrespace/mastodon
Merge pull request #386 from mitchhentges/file-drop-ui
On file-drag, show a border around textarea
This commit is contained in:
commit
e6657d7342
|
@ -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'>
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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'])),
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue