Repository: mui/material-ui (TypeScript)
Date: 2019-06-10 18:08:47+00:00
Task type: Bug Fix

Issue:
[ButtonBase] Ripple Effect is duplicated when dragging an image
- [x] This is a v1.x issue (v0.x is no longer maintained).
- [x] I have searched the [issues](https://github.com/mui-org/material-ui/issues) of this repository and believe that this is not a duplicate. (The issue seems similar to #7537)

## Expected Behavior

After the mouse click has released and the animation completed the ripple effect should dissapear.

## Current Behavior

Currently if a Button exists with an Image inside of it, clicking and moving the mouse causes the image to be selected. On Chrome (both Firefox and Microsoft Edge do not have this behavior) based browsers this is preventing the ripple from being removed afterwards. If this is done only once this only slightly highlights the button and is removed after another click. However, if multiple drags are done on the same button all but the last ripple remain indefinitely.

In my application this is the code that produces this error.

```
              <ButtonBase>
                <img
                  src='https://i.ytimg.com/vi/GRnALgoI8-4/hqdefault.jpg'/>
              </ButtonBase>
```

[Example here](https://codesandbox.io/s/k04wj1141r)

## Steps to Reproduce (for bugs)

1. Create a button with an image inside of it
2. Click on the button
3. Before releasing the mouse click and drag (Chrome will display the dragged image icon)
4. Release the mouse, the ripple effect remains.
5. Repeat 2-4 to make the effect deeper.

## Your Environment

| Tech         | Version |
|--------------|---------|
| Material-UI  | v1.2.0  |
| React        |  v16.2.0       |
| browser      |  Vivaldi 1.10.867.38 and Google Chrome 66.0.3359.181 |
| etc          | Windows 10 64bit, build 17134.48  |



Issue discussion:
@runewake2 The ripple disappear as soon as your mouse leaves the button base. I think that we are good here.
Plus the `onMouseUp` event doesn't trigger when dragging the image. I'm not sure we can do anything about it.
@runewake2 Try a few small click-drags within the ButtonBase one after the next. Then, each time you mouseover, one layer of ripple will be removed.
You're right, it does seem to pop the effects off one at a time if you mouse over repeatedly. Would it be possible to remove all the effects when removing the mouse so mousing over once removed all the left behind effects?
@runewake2 I have found two workarounds, non I think that worth taking the risk to be moved into the core. I'm keeping it here documented. In the future, we can revisit the tradeoff.

```jsx
  <ButtonBase
    onDragStart={event => {
      // Workaround 1    
      event.preventDefault();
    }}
  >
    <img
      style={{
        // Workaround 2
        pointerEvents: "none"
      }}
      src="https://i.ytimg.com/vi/GRnALgoI8-4/hqdefault.jpg"
    />
  </ButtonBase>
```
A solution was found in https://github.com/mui-org/material-ui/issues/15937#issuecomment-499848759.

Solution patch:
diff --git a/packages/material-ui/src/ButtonBase/ButtonBase.js b/packages/material-ui/src/ButtonBase/ButtonBase.js
--- a/packages/material-ui/src/ButtonBase/ButtonBase.js
+++ b/packages/material-ui/src/ButtonBase/ButtonBase.js
@@ -92,6 +92,7 @@ const ButtonBase = React.forwardRef(function ButtonBase(props, ref) {
     onTouchEnd,
     onTouchMove,
     onTouchStart,
+    onDragEnd,
     tabIndex = 0,
     TouchRippleProps,
     type = 'button',
@@ -145,6 +146,7 @@ const ButtonBase = React.forwardRef(function ButtonBase(props, ref) {
   }
 
   const handleMouseDown = useRippleHandler('start', onMouseDown);
+  const handleDragEnd = useRippleHandler('stop', onDragEnd);
   const handleMouseUp = useRippleHandler('stop', onMouseUp);
   const handleMouseLeave = useRippleHandler('stop', event => {
     if (focusVisible) {
@@ -282,6 +284,7 @@ const ButtonBase = React.forwardRef(function ButtonBase(props, ref) {
       onMouseDown={handleMouseDown}
       onMouseLeave={handleMouseLeave}
       onMouseUp={handleMouseUp}
+      onDragEnd={handleDragEnd}
       onTouchEnd={handleTouchEnd}
       onTouchMove={handleTouchMove}
       onTouchStart={handleTouchStart}
@@ -376,6 +379,10 @@ ButtonBase.propTypes = {
    * @ignore
    */
   onClick: PropTypes.func,
+  /**
+   * @ignore
+   */
+  onDragEnd: PropTypes.func,
   /**
    * @ignore
    */


Test patch:
diff --git a/packages/material-ui/src/ButtonBase/ButtonBase.test.js b/packages/material-ui/src/ButtonBase/ButtonBase.test.js
--- a/packages/material-ui/src/ButtonBase/ButtonBase.test.js
+++ b/packages/material-ui/src/ButtonBase/ButtonBase.test.js
@@ -113,6 +113,7 @@ describe('<ButtonBase />', () => {
         'onMouseDown',
         'onMouseLeave',
         'onMouseUp',
+        'onDragEnd',
         'onTouchEnd',
         'onTouchStart',
       ];
@@ -234,6 +235,26 @@ describe('<ButtonBase />', () => {
         assert.strictEqual(wrapper.find('.ripple-visible .child-leaving').length, 3);
         assert.strictEqual(wrapper.find('.ripple-visible .child:not(.child-leaving)').length, 0);
       });
+
+      it('should start the ripple when the mouse is pressed 4', () => {
+        act(() => {
+          wrapper.simulate('mouseDown');
+        });
+        wrapper.update();
+
+        assert.strictEqual(wrapper.find('.ripple-visible .child-leaving').length, 3);
+        assert.strictEqual(wrapper.find('.ripple-visible .child:not(.child-leaving)').length, 1);
+      });
+
+      it('should stop the ripple when dragging has finished', () => {
+        act(() => {
+          wrapper.simulate('dragEnd');
+        });
+        wrapper.update();
+
+        assert.strictEqual(wrapper.find('.ripple-visible .child-leaving').length, 4);
+        assert.strictEqual(wrapper.find('.ripple-visible .child:not(.child-leaving)').length, 0);
+      });
     });
 
     it('should center the ripple', () => {