<div id="root" />
/**
 * A circle avatar 
 */
function ChatHead({ src, ...props }) {
  return (
    <img draggable="false"
      src={ src }
      style={{  transition: 'all 300ms ease-in-out' }}
      className="br-100 pa1 ba b--black-10 h3 w3"
      alt="chat-head"
      { ...props } />
  );
}

/**
 * Draggable
 * A wrapper component for
 * making elements draggable
 */
class Draggable extends React.Component {
  
  constructor() {
    super();
    this.state = { 
      x: window.innerWidth / 2, 
      y: window.innerHeight / 2,
      dragging: false,
    };
  }

  onPanStart = e => {
    if (e.type === 'dragstart') {
      e.dataTransfer.setDragImage(getDragImage(), 0, 0);
    }
    this.setState({ dragging: true });
  };

  onPan = e => {
    if (e.clientX <= 0 || e.clientY <= 0) return false;
    this.setState(getPan(e));
  };

  onPanEnd = e => {
    this.setState({ dragging: false });
  };
  
  render() {
    const { x, y, dragging } = this.state;
    const { children } = this.props;
    
    return (
      <div draggable="true"
        className="dib move"
        style={{
          display: 'inline-block',
          cursor: 'move',
          WebkitTransform: `translate3d(${ x - 32 }px, ${ y - 32 }px, 0)`,
          transform: `translate3d(${ x - 32 }px, ${ y - 32 }px, 0)`,
        }}
        onTouchStart={ this.onPanStart }
        onDragStart={ this.onPanStart }
        onDrag={ this.onPan }
        onTouchMove={ this.onPan }
        onTouchEnd={ this.onPanEnd }
        onDragEnd={ this.onPanEnd}>
        { children }
      </div>
    ); 
  }
}


/**
 * Root node of the application
 */
function App() {
  return (
    <Draggable>
      <ChatHead
        src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/149125/profile.jpg" 
      />
    </Draggable>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));

/**
 * Utils
 */
function getPan(e) {
  if (e.type.includes('drag')) {
    return { x: e.clientX, y: e.clientY };
  }

  const touch = e.targetTouches[0];
  return { x: touch.clientX, y: touch.clientY };
}

function getDragImage() {
  let img = new Image();
  img.src = 'fake.gif';
  return img;
}
View Compiled

External CSS

  1. https://unpkg.com/tachyons@4.5.3/css/tachyons.min.css

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.min.js