Merge pull request #386 from mitchhentges/file-drop-ui
On file-drag, show a border around textarea
This commit is contained in:
		
						commit
						e88cf0ad41
					
				
					 5 changed files with 54 additions and 6 deletions
				
			
		| 
						 | 
				
			
			@ -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 a new issue