void,
+ onWheelDelta: (offset: number, horizontal: boolean) => void,
): [(e: WheelEvent) => void, (e: FireFoxDOMMouseScrollEvent) => void] {
const offsetRef = useRef(0);
const nextFrameRef = useRef
(null);
@@ -35,15 +35,25 @@ export default function useFrameWheel(
isScrollAtRight,
);
- function onWheelY(event: WheelEvent, deltaY: number) {
+ function onWheelY(e: WheelEvent, deltaY: number) {
raf.cancel(nextFrameRef.current);
- offsetRef.current += deltaY;
- wheelValueRef.current = deltaY;
-
// Do nothing when scroll at the edge, Skip check when is in scroll
if (originScroll(false, deltaY)) return;
+ // Skip if nest List has handled this event
+ const event = e as WheelEvent & {
+ _virtualHandled?: boolean;
+ };
+ if (!event._virtualHandled) {
+ event._virtualHandled = true;
+ } else {
+ return;
+ }
+
+ offsetRef.current += deltaY;
+ wheelValueRef.current = deltaY;
+
// Proxy of scroll events
if (!isFF) {
event.preventDefault();
@@ -53,7 +63,7 @@ export default function useFrameWheel(
// Patch a multiple for Firefox to fix wheel number too small
// ref: https://github.com/ant-design/ant-design/issues/26372#issuecomment-679460266
const patchMultiple = isMouseScrollRef.current ? 10 : 1;
- onWheelDelta(offsetRef.current * patchMultiple);
+ onWheelDelta(offsetRef.current * patchMultiple, false);
offsetRef.current = 0;
});
}
diff --git a/src/hooks/useMobileTouchMove.ts b/src/hooks/useMobileTouchMove.ts
index 17740e9e..74945628 100644
--- a/src/hooks/useMobileTouchMove.ts
+++ b/src/hooks/useMobileTouchMove.ts
@@ -7,7 +7,12 @@ const SMOOTH_PTG = 14 / 15;
export default function useMobileTouchMove(
inVirtual: boolean,
listRef: React.RefObject,
- callback: (isHorizontal: boolean, offset: number, smoothOffset?: boolean) => boolean,
+ callback: (
+ isHorizontal: boolean,
+ offset: number,
+ smoothOffset: boolean,
+ e?: TouchEvent,
+ ) => boolean,
) {
const touchedRef = useRef(false);
const touchXRef = useRef(0);
@@ -34,22 +39,27 @@ export default function useMobileTouchMove(
touchYRef.current = currentY;
}
- if (callback(isHorizontal, isHorizontal ? offsetX : offsetY)) {
+ const scrollHandled = callback(isHorizontal, isHorizontal ? offsetX : offsetY, false, e);
+ if (scrollHandled) {
e.preventDefault();
}
+
// Smooth interval
clearInterval(intervalRef.current);
- intervalRef.current = setInterval(() => {
- if (isHorizontal) {
- offsetX *= SMOOTH_PTG;
- } else {
- offsetY *= SMOOTH_PTG;
- }
- const offset = Math.floor(isHorizontal ? offsetX : offsetY);
- if (!callback(isHorizontal, offset, true) || Math.abs(offset) <= 0.1) {
- clearInterval(intervalRef.current);
- }
- }, 16);
+
+ if (scrollHandled) {
+ intervalRef.current = setInterval(() => {
+ if (isHorizontal) {
+ offsetX *= SMOOTH_PTG;
+ } else {
+ offsetY *= SMOOTH_PTG;
+ }
+ const offset = Math.floor(isHorizontal ? offsetX : offsetY);
+ if (!callback(isHorizontal, offset, true) || Math.abs(offset) <= 0.1) {
+ clearInterval(intervalRef.current);
+ }
+ }, 16);
+ }
}
};
diff --git a/tests/scroll.test.js b/tests/scroll.test.js
index 314c1db2..8eee0a43 100644
--- a/tests/scroll.test.js
+++ b/tests/scroll.test.js
@@ -1,10 +1,9 @@
import '@testing-library/jest-dom';
-import { createEvent, fireEvent, render } from '@testing-library/react';
+import { act, createEvent, fireEvent, render } from '@testing-library/react';
import { mount } from 'enzyme';
import { _rs as onLibResize } from 'rc-resize-observer/lib/utils/observerUtil';
import { resetWarned } from 'rc-util/lib/warning';
import React from 'react';
-import { act } from 'react-dom/test-utils';
import List from '../src';
import { spyElementPrototypes } from './utils/domHook';
@@ -51,11 +50,13 @@ describe('List.Scroll', () => {
});
function genList(props, func = mount) {
- let node = (
-
- {({ id }) => {id}}
-
- );
+ const mergedProps = {
+ component: 'ul',
+ itemKey: 'id',
+ children: ({ id }) => {id},
+ ...props,
+ };
+ let node =
;
if (props.ref) {
node = {node}
;
@@ -494,4 +495,43 @@ describe('List.Scroll', () => {
expect(container.querySelector('.rc-virtual-list-scrollbar-thumb')).toBeVisible();
});
+
+ it('nest scroll', async () => {
+ const { container } = genList(
+ {
+ itemHeight: 20,
+ height: 100,
+ data: genData(100),
+ children: ({ id }) =>
+ id === '0' ? (
+
+
+ {({ id }) => {id}}
+
+
+ ) : (
+
+ ),
+ },
+ render,
+ );
+
+ fireEvent.wheel(container.querySelector('ul ul li'), {
+ deltaY: 10,
+ });
+
+ await act(async () => {
+ jest.advanceTimersByTime(1000000);
+ await Promise.resolve();
+ });
+
+ expect(container.querySelectorAll('[data-dev-offset-top]')[0]).toHaveAttribute(
+ 'data-dev-offset-top',
+ '0',
+ );
+ expect(container.querySelectorAll('[data-dev-offset-top]')[1]).toHaveAttribute(
+ 'data-dev-offset-top',
+ '10',
+ );
+ });
});
diff --git a/tests/touch.test.js b/tests/touch.test.js
index 12691ab7..415bc87c 100644
--- a/tests/touch.test.js
+++ b/tests/touch.test.js
@@ -1,7 +1,8 @@
-import React from 'react';
+import { act, fireEvent, render } from '@testing-library/react';
import { mount } from 'enzyme';
-import { spyElementPrototypes } from './utils/domHook';
+import React from 'react';
import List from '../src';
+import { spyElementPrototypes } from './utils/domHook';
function genData(count) {
return new Array(count).fill(null).map((_, index) => ({ id: String(index) }));
@@ -123,11 +124,55 @@ describe('List.Touch', () => {
const touchEvent = new Event('touchstart');
touchEvent.preventDefault = preventDefault;
- wrapper
- .find('.rc-virtual-list-scrollbar')
- .instance()
- .dispatchEvent(touchEvent);
+ wrapper.find('.rc-virtual-list-scrollbar').instance().dispatchEvent(touchEvent);
expect(preventDefault).toHaveBeenCalled();
});
+
+ it('nest touch', async () => {
+ const { container } = render(
+
+ {({ id }) =>
+ id === '0' ? (
+
+
+ {({ id }) => {id}}
+
+
+ ) : (
+
+ )
+ }
+
,
+ );
+
+ const targetLi = container.querySelector('ul ul li');
+
+ fireEvent.touchStart(targetLi, {
+ touches: [{ pageY: 0 }],
+ });
+
+ fireEvent.touchMove(targetLi, {
+ touches: [{ pageY: -1 }],
+ });
+
+ await act(async () => {
+ jest.advanceTimersByTime(1000000);
+ await Promise.resolve();
+ });
+
+ expect(container.querySelectorAll('[data-dev-offset-top]')[0]).toHaveAttribute(
+ 'data-dev-offset-top',
+ '0',
+ );
+
+ // inner not to be 0
+ expect(container.querySelectorAll('[data-dev-offset-top]')[1]).toHaveAttribute(
+ 'data-dev-offset-top',
+ );
+ expect(container.querySelectorAll('[data-dev-offset-top]')[1]).not.toHaveAttribute(
+ 'data-dev-offset-top',
+ '0',
+ );
+ });
});