Refactor composer Dropdown's component a bit to make it closer to upstream
This commit is contained in:
		
							parent
							
								
									381dbb6569
								
							
						
					
					
						commit
						6d2b0fa3f0
					
				@ -12,33 +12,71 @@ import DropdownMenu from './dropdown_menu';
 | 
				
			|||||||
import { isUserTouching } from 'flavours/glitch/util/is_mobile';
 | 
					import { isUserTouching } from 'flavours/glitch/util/is_mobile';
 | 
				
			||||||
import { assignHandlers } from 'flavours/glitch/util/react_helpers';
 | 
					import { assignHandlers } from 'flavours/glitch/util/react_helpers';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//  Handlers.
 | 
					//  The component.
 | 
				
			||||||
const handlers = {
 | 
					export default class ComposerOptionsDropdown extends React.PureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  //  Closes the dropdown.
 | 
					  static propTypes = {
 | 
				
			||||||
  handleClose () {
 | 
					    active: PropTypes.bool,
 | 
				
			||||||
    this.setState({ open: false });
 | 
					    disabled: PropTypes.bool,
 | 
				
			||||||
  },
 | 
					    icon: PropTypes.string,
 | 
				
			||||||
 | 
					    items: PropTypes.arrayOf(PropTypes.shape({
 | 
				
			||||||
 | 
					      icon: PropTypes.string,
 | 
				
			||||||
 | 
					      meta: PropTypes.node,
 | 
				
			||||||
 | 
					      name: PropTypes.string.isRequired,
 | 
				
			||||||
 | 
					      on: PropTypes.bool,
 | 
				
			||||||
 | 
					      text: PropTypes.node,
 | 
				
			||||||
 | 
					    })).isRequired,
 | 
				
			||||||
 | 
					    onModalOpen: PropTypes.func,
 | 
				
			||||||
 | 
					    onModalClose: PropTypes.func,
 | 
				
			||||||
 | 
					    title: PropTypes.string,
 | 
				
			||||||
 | 
					    value: PropTypes.string,
 | 
				
			||||||
 | 
					    onChange: PropTypes.func,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  //  The enter key toggles the dropdown's open state, and the escape
 | 
					  state = {
 | 
				
			||||||
  //  key closes it.
 | 
					    needsModalUpdate: false,
 | 
				
			||||||
  handleKeyDown ({ key }) {
 | 
					    open: false,
 | 
				
			||||||
    const {
 | 
					    placement: 'bottom',
 | 
				
			||||||
      handleClose,
 | 
					  };
 | 
				
			||||||
      handleToggle,
 | 
					
 | 
				
			||||||
    } = this.handlers;
 | 
					  //  Toggles opening and closing the dropdown.
 | 
				
			||||||
    switch (key) {
 | 
					  handleToggle = ({ target }) => {
 | 
				
			||||||
 | 
					    const { onModalOpen } = this.props;
 | 
				
			||||||
 | 
					    const { open } = this.state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (isUserTouching()) {
 | 
				
			||||||
 | 
					      if (this.state.open) {
 | 
				
			||||||
 | 
					        this.props.onModalClose();
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        const modal = this.handleMakeModal();
 | 
				
			||||||
 | 
					        if (modal && onModalOpen) {
 | 
				
			||||||
 | 
					          onModalOpen(modal);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      const { top } = target.getBoundingClientRect();
 | 
				
			||||||
 | 
					      this.setState({ placement: top * 2 < innerHeight ? 'bottom' : 'top' });
 | 
				
			||||||
 | 
					      this.setState({ open: !this.state.open });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  handleKeyDown = (e) => {
 | 
				
			||||||
 | 
					    switch (e.key) {
 | 
				
			||||||
    case 'Enter':
 | 
					    case 'Enter':
 | 
				
			||||||
      handleToggle(key);
 | 
					      this.handleToggle(key);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case 'Escape':
 | 
					    case 'Escape':
 | 
				
			||||||
      handleClose();
 | 
					      this.handleClose();
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  handleClose = () => {
 | 
				
			||||||
 | 
					    this.setState({ open: false });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  //  Creates an action modal object.
 | 
					  //  Creates an action modal object.
 | 
				
			||||||
  handleMakeModal () {
 | 
					  handleMakeModal = () => {
 | 
				
			||||||
    const component = this;
 | 
					    const component = this;
 | 
				
			||||||
    const {
 | 
					    const {
 | 
				
			||||||
      items,
 | 
					      items,
 | 
				
			||||||
@ -76,85 +114,37 @@ const handlers = {
 | 
				
			|||||||
        })
 | 
					        })
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  },
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
  //  Toggles opening and closing the dropdown.
 | 
					 | 
				
			||||||
  handleToggle ({ target }) {
 | 
					 | 
				
			||||||
    const { handleMakeModal } = this.handlers;
 | 
					 | 
				
			||||||
    const { onModalOpen } = this.props;
 | 
					 | 
				
			||||||
    const { open } = this.state;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //  If this is a touch device, we open a modal instead of the
 | 
					 | 
				
			||||||
    //  dropdown.
 | 
					 | 
				
			||||||
    if (isUserTouching()) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      //  This gets the modal to open.
 | 
					 | 
				
			||||||
      const modal = handleMakeModal();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      //  If we can, we then open the modal.
 | 
					 | 
				
			||||||
      if (modal && onModalOpen) {
 | 
					 | 
				
			||||||
        onModalOpen(modal);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const { top } = target.getBoundingClientRect();
 | 
					 | 
				
			||||||
    this.setState({ placement: top * 2 < innerHeight ? 'bottom' : 'top' });
 | 
					 | 
				
			||||||
    //  Otherwise, we just set our state to open.
 | 
					 | 
				
			||||||
    this.setState({ open: !open });
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  //  If our modal is open and our props update, we need to also update
 | 
					  //  If our modal is open and our props update, we need to also update
 | 
				
			||||||
  //  the modal.
 | 
					  //  the modal.
 | 
				
			||||||
  handleUpdate () {
 | 
					  handleUpdate = () => {
 | 
				
			||||||
    const { handleMakeModal } = this.handlers;
 | 
					 | 
				
			||||||
    const { onModalOpen } = this.props;
 | 
					    const { onModalOpen } = this.props;
 | 
				
			||||||
    const { needsModalUpdate } = this.state;
 | 
					    const { needsModalUpdate } = this.state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //  Gets our modal object.
 | 
					    //  Gets our modal object.
 | 
				
			||||||
    const modal = handleMakeModal();
 | 
					    const modal = this.handleMakeModal();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //  Reopens the modal with the new object.
 | 
					    //  Reopens the modal with the new object.
 | 
				
			||||||
    if (needsModalUpdate && modal && onModalOpen) {
 | 
					    if (needsModalUpdate && modal && onModalOpen) {
 | 
				
			||||||
      onModalOpen(modal);
 | 
					      onModalOpen(modal);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//  The component.
 | 
					 | 
				
			||||||
export default class ComposerOptionsDropdown extends React.PureComponent {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  //  Constructor.
 | 
					 | 
				
			||||||
  constructor (props) {
 | 
					 | 
				
			||||||
    super(props);
 | 
					 | 
				
			||||||
    assignHandlers(this, handlers);
 | 
					 | 
				
			||||||
    this.state = {
 | 
					 | 
				
			||||||
      needsModalUpdate: false,
 | 
					 | 
				
			||||||
      open: false,
 | 
					 | 
				
			||||||
      placement: 'bottom',
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  //  Updates our modal as necessary.
 | 
					  //  Updates our modal as necessary.
 | 
				
			||||||
  componentDidUpdate (prevProps) {
 | 
					  componentDidUpdate (prevProps) {
 | 
				
			||||||
    const { handleUpdate } = this.handlers;
 | 
					 | 
				
			||||||
    const { items } = this.props;
 | 
					    const { items } = this.props;
 | 
				
			||||||
    const { needsModalUpdate } = this.state;
 | 
					    const { needsModalUpdate } = this.state;
 | 
				
			||||||
    if (needsModalUpdate && items.find(
 | 
					    if (needsModalUpdate && items.find(
 | 
				
			||||||
      (item, i) => item.on !== prevProps.items[i].on
 | 
					      (item, i) => item.on !== prevProps.items[i].on
 | 
				
			||||||
    )) {
 | 
					    )) {
 | 
				
			||||||
      handleUpdate();
 | 
					      this.handleUpdate();
 | 
				
			||||||
      this.setState({ needsModalUpdate: false });
 | 
					      this.setState({ needsModalUpdate: false });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  //  Rendering.
 | 
					  //  Rendering.
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
    const {
 | 
					 | 
				
			||||||
      handleClose,
 | 
					 | 
				
			||||||
      handleKeyDown,
 | 
					 | 
				
			||||||
      handleToggle,
 | 
					 | 
				
			||||||
    } = this.handlers;
 | 
					 | 
				
			||||||
    const {
 | 
					    const {
 | 
				
			||||||
      active,
 | 
					      active,
 | 
				
			||||||
      disabled,
 | 
					      disabled,
 | 
				
			||||||
@ -175,7 +165,7 @@ export default class ComposerOptionsDropdown extends React.PureComponent {
 | 
				
			|||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div
 | 
					      <div
 | 
				
			||||||
        className={computedClass}
 | 
					        className={computedClass}
 | 
				
			||||||
        onKeyDown={handleKeyDown}
 | 
					        onKeyDown={this.handleKeyDown}
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <IconButton
 | 
					        <IconButton
 | 
				
			||||||
          active={open || active}
 | 
					          active={open || active}
 | 
				
			||||||
@ -183,7 +173,7 @@ export default class ComposerOptionsDropdown extends React.PureComponent {
 | 
				
			|||||||
          disabled={disabled}
 | 
					          disabled={disabled}
 | 
				
			||||||
          icon={icon}
 | 
					          icon={icon}
 | 
				
			||||||
          inverted
 | 
					          inverted
 | 
				
			||||||
          onClick={handleToggle}
 | 
					          onClick={this.handleToggle}
 | 
				
			||||||
          size={18}
 | 
					          size={18}
 | 
				
			||||||
          style={{
 | 
					          style={{
 | 
				
			||||||
            height: null,
 | 
					            height: null,
 | 
				
			||||||
@ -200,7 +190,7 @@ export default class ComposerOptionsDropdown extends React.PureComponent {
 | 
				
			|||||||
          <DropdownMenu
 | 
					          <DropdownMenu
 | 
				
			||||||
            items={items}
 | 
					            items={items}
 | 
				
			||||||
            onChange={onChange}
 | 
					            onChange={onChange}
 | 
				
			||||||
            onClose={handleClose}
 | 
					            onClose={this.handleClose}
 | 
				
			||||||
            value={value}
 | 
					            value={value}
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
        </Overlay>
 | 
					        </Overlay>
 | 
				
			||||||
@ -209,22 +199,3 @@ export default class ComposerOptionsDropdown extends React.PureComponent {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
//  Props.
 | 
					 | 
				
			||||||
ComposerOptionsDropdown.propTypes = {
 | 
					 | 
				
			||||||
  active: PropTypes.bool,
 | 
					 | 
				
			||||||
  disabled: PropTypes.bool,
 | 
					 | 
				
			||||||
  icon: PropTypes.string,
 | 
					 | 
				
			||||||
  items: PropTypes.arrayOf(PropTypes.shape({
 | 
					 | 
				
			||||||
    icon: PropTypes.string,
 | 
					 | 
				
			||||||
    meta: PropTypes.node,
 | 
					 | 
				
			||||||
    name: PropTypes.string.isRequired,
 | 
					 | 
				
			||||||
    on: PropTypes.bool,
 | 
					 | 
				
			||||||
    text: PropTypes.node,
 | 
					 | 
				
			||||||
  })).isRequired,
 | 
					 | 
				
			||||||
  onChange: PropTypes.func,
 | 
					 | 
				
			||||||
  onModalClose: PropTypes.func,
 | 
					 | 
				
			||||||
  onModalOpen: PropTypes.func,
 | 
					 | 
				
			||||||
  title: PropTypes.string,
 | 
					 | 
				
			||||||
  value: PropTypes.string,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user