Merge pull request #386 from mitchhentges/file-drop-ui
On file-drag, show a border around textarea
This commit is contained in:
		| @ -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 { | ||||
|  | ||||
		Reference in New Issue
	
	Block a user