Skip to content

Commit

Permalink
[Slider] Better tracking of mouse events (#22557)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisinajar authored Sep 24, 2020
1 parent 1c2055a commit 867d66c
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 13 deletions.
39 changes: 26 additions & 13 deletions packages/material-ui/src/Slider/Slider.js
Original file line number Diff line number Diff line change
Expand Up @@ -668,11 +668,7 @@ const Slider = React.forwardRef(function Slider(props, ref) {

touchId.current = undefined;

const doc = ownerDocument(sliderRef.current);
doc.removeEventListener('mousemove', handleTouchMove);
doc.removeEventListener('mouseup', handleTouchEnd);
doc.removeEventListener('touchmove', handleTouchMove);
doc.removeEventListener('touchend', handleTouchEnd);
stopListening();
});

const handleTouchStart = useEventCallback((event) => {
Expand Down Expand Up @@ -701,25 +697,38 @@ const Slider = React.forwardRef(function Slider(props, ref) {
doc.addEventListener('touchend', handleTouchEnd);
});

const handleMouseMove = useEventCallback((event) => {
// require the left mouse button still be held
if (event.buttons === 1) {
handleTouchMove(event);
} else {
touchId.current = undefined;
stopListening();
}
});

const stopListening = React.useCallback(() => {
const doc = ownerDocument(sliderRef.current);
doc.removeEventListener('mousemove', handleMouseMove);
doc.removeEventListener('mouseup', handleTouchEnd);
doc.removeEventListener('touchmove', handleTouchMove);
doc.removeEventListener('touchend', handleTouchEnd);
}, [handleMouseMove, handleTouchEnd, handleTouchMove, sliderRef]);

React.useEffect(() => {
const { current: slider } = sliderRef;
slider.addEventListener('touchstart', handleTouchStart, {
passive: doesSupportTouchActionNone(),
});

const doc = ownerDocument(slider);

return () => {
slider.removeEventListener('touchstart', handleTouchStart, {
passive: doesSupportTouchActionNone(),
});

doc.removeEventListener('mousemove', handleTouchMove);
doc.removeEventListener('mouseup', handleTouchEnd);
doc.removeEventListener('touchmove', handleTouchMove);
doc.removeEventListener('touchend', handleTouchEnd);
stopListening();
};
}, [handleTouchEnd, handleTouchMove, handleTouchStart]);
}, [stopListening, handleTouchStart, sliderRef]);

React.useEffect(() => {
if (disabled) {
Expand All @@ -732,6 +741,10 @@ const Slider = React.forwardRef(function Slider(props, ref) {
}, [disabled, handleTouchEnd, handleTouchMove]);

const handleMouseDown = useEventCallback((event) => {
// don't listen to right clicks
if (event.buttons === 2) {
return;
}
if (onMouseDown) {
onMouseDown(event);
}
Expand All @@ -748,7 +761,7 @@ const Slider = React.forwardRef(function Slider(props, ref) {
}

const doc = ownerDocument(sliderRef.current);
doc.addEventListener('mousemove', handleTouchMove);
doc.addEventListener('mousemove', handleMouseMove);
doc.addEventListener('mouseup', handleTouchEnd);
});

Expand Down
35 changes: 35 additions & 0 deletions packages/material-ui/src/Slider/Slider.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,41 @@ describe('<Slider />', () => {
expect(handleChange.args[1][1]).to.deep.equal([22, 30]);
expect(handleChange.args[2][1]).to.equal(handleChange.args[1][1]);
});

it('should not react to right clicks', () => {
const handleMouseDown = spy();
const { getByRole } = render(
<Slider onMouseDown={handleMouseDown} defaultValue={30} step={10} marks />,
);
const thumb = getByRole('slider');
const rightClick = { buttons: 2 };
fireEvent.mouseDown(thumb, rightClick);
expect(handleMouseDown.callCount).to.equal(0);
});

it('should not remain focused if mouse was released outside of the window', () => {
const handleChange = spy();
const { container, getByRole } = render(
<Slider onChange={handleChange} defaultValue={30} step={10} marks />,
);

stub(container.firstChild, 'getBoundingClientRect').callsFake(() => ({
width: 100,
height: 10,
bottom: 10,
left: 0,
}));

const thumb = getByRole('slider');
const noButtons = { button: 0, buttons: 0 };
const leftMouseButton = { button: 0, buttons: 1, clientX: 20 };
fireEvent.mouseDown(thumb, leftMouseButton);
expect(handleChange.callCount).to.equal(1);
fireEvent.mouseMove(thumb, leftMouseButton);
expect(handleChange.callCount).to.equal(2);
fireEvent.mouseMove(thumb, noButtons);
expect(handleChange.callCount).to.equal(2);
});
});

it('should not break when initial value is out of range', () => {
Expand Down

0 comments on commit 867d66c

Please sign in to comment.