diff --git a/src/hooks/useDrag.ts b/src/hooks/useDrag.ts
index a497e3972..0257c6f08 100644
--- a/src/hooks/useDrag.ts
+++ b/src/hooks/useDrag.ts
@@ -58,7 +58,7 @@ function useDrag(
document.removeEventListener('mousemove', mouseMoveEventRef.current);
}
if (mouseUpEventRef.current) {
- document.removeEventListener('mouseup', mouseUpEventRef.current);
+ document.removeEventListener('mouseup', mouseUpEventRef.current, true);
}
if (touchEventTargetRef.current) {
if (mouseMoveEventRef.current) {
@@ -211,9 +211,11 @@ function useDrag(
// End
const onMouseUp: EventListener = (event) => {
- event.preventDefault();
+ if (event.type === 'touchend') {
+ event.preventDefault();
+ }
- document.removeEventListener('mouseup', onMouseUp);
+ document.removeEventListener('mouseup', onMouseUp, true);
document.removeEventListener('mousemove', onMouseMove);
if (touchEventTargetRef.current) {
if (mouseMoveEventRef.current) {
@@ -233,7 +235,7 @@ function useDrag(
setDraggingDelete(false);
};
- document.addEventListener('mouseup', onMouseUp);
+ document.addEventListener('mouseup', onMouseUp, true);
document.addEventListener('mousemove', onMouseMove);
e.currentTarget.addEventListener('touchend', onMouseUp);
e.currentTarget.addEventListener('touchmove', onMouseMove);
diff --git a/tests/Range.test.tsx b/tests/Range.test.tsx
index dd6ad0044..32323733b 100644
--- a/tests/Range.test.tsx
+++ b/tests/Range.test.tsx
@@ -94,6 +94,28 @@ describe('Range', () => {
fireEvent(container.getElementsByClassName(element)[0], touchMove);
}
+ it('prevents the native default action when a touch drag ends', () => {
+ const onChangeComplete = jest.fn();
+ const { container } = render(
+ ,
+ );
+ const handle = container.getElementsByClassName('rc-slider-handle')[0];
+ const touchStart = createEvent.touchStart(handle, {
+ touches: [{}],
+ targetTouches: [{}],
+ });
+ (touchStart as any).targetTouches[0].pageX = 20;
+ fireEvent(handle, touchStart);
+
+ const touchEnd = createEvent.touchEnd(handle);
+ const preventDefault = jest.fn();
+ Object.defineProperty(touchEnd, 'preventDefault', { value: preventDefault });
+ fireEvent(handle, touchEnd);
+
+ expect(preventDefault).toHaveBeenCalledTimes(1);
+ expect(onChangeComplete).toHaveBeenCalledWith([20, 40]);
+ });
+
it('should render Range with correct DOM structure', () => {
const { asFragment } = render();
expect(asFragment().firstChild).toMatchSnapshot();
@@ -140,9 +162,7 @@ describe('Range', () => {
});
it('should render Range without tabIndex (equal null) correctly', () => {
- const { container } = render(
- ,
- );
+ const { container } = render();
expect(container.getElementsByClassName('rc-slider-handle')[0]).not.toHaveAttribute('tabIndex');
expect(container.getElementsByClassName('rc-slider-handle')[1]).not.toHaveAttribute('tabIndex');
});
@@ -872,7 +892,12 @@ describe('Range', () => {
it('respects handle disabled state and boolean disabled fallback', () => {
const onChange = jest.fn();
const { container, rerender } = render(
- ,
+ ,
);
const disabledHandle = getHandle(container, 0);
@@ -909,17 +934,23 @@ describe('Range', () => {
expect(onChange).toHaveBeenCalledWith([0, 10, 100]);
onChange.mockClear();
- rerender();
+ rerender(
+ ,
+ );
doMouseDown(container, 10, 'rc-slider', true);
fireEvent.mouseUp(document);
expect(onChange).not.toHaveBeenCalled();
- rerender();
+ rerender(
+ ,
+ );
doMouseDown(container, 90, 'rc-slider', true);
fireEvent.mouseUp(document);
expect(onChange).not.toHaveBeenCalled();
- rerender();
+ rerender(
+ ,
+ );
doMouseDown(container, 10, 'rc-slider', true);
fireEvent.mouseUp(document);
expect(onChange).not.toHaveBeenCalled();
@@ -963,7 +994,12 @@ describe('Range', () => {
it('disables draggableTrack only when rendered handles are disabled', () => {
const onChange = jest.fn();
const { container, unmount } = render(
- ,
+ ,
);
const track = container.getElementsByClassName('rc-slider-track')[0];
@@ -1002,7 +1038,12 @@ describe('Range', () => {
it('keeps keyboard movement inside disabled handle boundaries', () => {
const onChange = jest.fn();
const { container, unmount } = render(
- ,
+ ,
);
repeatKeyDown(getHandle(container, 0), keyCode.RIGHT, 50);
@@ -1012,7 +1053,12 @@ describe('Range', () => {
onChange.mockClear();
const { container: boundaryContainer } = render(
- ,
+ ,
);
const middleHandle = getHandle(boundaryContainer, 1);
@@ -1029,7 +1075,13 @@ describe('Range', () => {
it('respects pushable boundaries around disabled handles', () => {
const onChange = jest.fn();
const { container } = render(
- ,
+ ,
);
repeatKeyDown(getHandle(container, 0), keyCode.UP, 30);
@@ -1046,7 +1098,13 @@ describe('Range', () => {
it('respects disabled boundaries with allowCross=false and step=null', () => {
const onChange = jest.fn();
const { container, unmount } = render(
- ,
+ ,
);
repeatKeyDown(getHandle(container, 0), keyCode.RIGHT, 50);
@@ -1056,7 +1114,15 @@ describe('Range', () => {
onChange.mockClear();
const { container: stepContainer } = render(
- ,
+ ,
);
fireEvent.keyDown(getHandle(stepContainer, 0), { keyCode: keyCode.RIGHT });
diff --git a/tests/Slider.test.js b/tests/Slider.test.js
index a145d0300..1adebb330 100644
--- a/tests/Slider.test.js
+++ b/tests/Slider.test.js
@@ -659,6 +659,35 @@ describe('Slider', () => {
expect(onAfterChange).toHaveBeenCalledWith(20);
});
+ it('should finish dragging when a parent stops mouseup propagation', () => {
+ const onChange = jest.fn();
+ const onChangeComplete = jest.fn();
+ const onParentMouseUp = jest.fn((event) => event.stopPropagation());
+ const { container, getByTestId } = render(
+
+
+
,
+ );
+ const handle = container.querySelector('.rc-slider-handle');
+
+ fireEvent.mouseDown(handle, { pageX: 50 });
+ const firstMove = createEvent.mouseMove(document);
+ firstMove.pageX = 60;
+ fireEvent(document, firstMove);
+ expect(onChange).toHaveBeenCalled();
+ const lastDraggedValue = onChange.mock.calls[onChange.mock.calls.length - 1][0];
+
+ onChange.mockClear();
+ fireEvent.mouseUp(getByTestId('parent'));
+ expect(onParentMouseUp.mock.calls[0][0].defaultPrevented).toBe(false);
+ expect(onChangeComplete).toHaveBeenCalledWith(lastDraggedValue);
+
+ const moveAfterRelease = createEvent.mouseMove(document);
+ moveAfterRelease.pageX = 70;
+ fireEvent(document, moveAfterRelease);
+ expect(onChange).not.toHaveBeenCalled();
+ });
+
// https://github.com/react-component/slider/pull/948
it('could drag handler after click tracker', () => {
const onChange = jest.fn();