Skip to content

Commit

Permalink
fix(HorizontalScroll): fix scroll when mouse over arrow
Browse files Browse the repository at this point in the history
  • Loading branch information
EldarMuhamethanov committed Nov 2, 2024
1 parent 77eeaa0 commit b661694
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ const setup = (element: HTMLElement, startScrollLeft = 0) => {

jest.spyOn(element.firstElementChild!, 'scrollWidth', 'get').mockImplementation(() => 500);

// @ts-expect-error: TS2322 есть другой тип, но в компоненте он не используется
element.scrollBy = (options?: ScrollToOptions) => {
scrollLeft = scrollLeft + (options?.left || 0);
};

return {
get scrollLeft() {
return scrollLeft;
Expand Down Expand Up @@ -176,6 +181,34 @@ describe('HorizontalScroll', () => {
expect(mockedData.scrollLeft).toBe(200);
});
});

it('scroll by arrow', () => {
const ref: React.MutableRefObject<HTMLDivElement | null> = {
current: null,
};
render(
<HorizontalScroll getRef={ref} data-testid="horizontal-scroll">
<div style={{ width: '1800px', height: '50px' }} />
</HorizontalScroll>,
);

const mockedData = setup(ref.current!, 50);

fireEvent.mouseEnter(screen.getByTestId('horizontal-scroll'));

const arrowLeft = screen.getByTestId('ScrollArrowLeft');
const arrowRight = screen.getByTestId('ScrollArrowRight');

fireEvent.wheel(arrowRight, {
deltaX: 20,
});
expect(mockedData.scrollLeft).toBe(70);

fireEvent.wheel(arrowLeft, {
deltaX: 20,
});
expect(mockedData.scrollLeft).toBe(90);
});
});

function mockRef(element: HTMLDivElement) {
Expand Down
51 changes: 23 additions & 28 deletions packages/vkui/src/components/HorizontalScroll/HorizontalScroll.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
'use client';

import * as React from 'react';
import { classNames, noop } from '@vkontakte/vkjs';
import { classNames } from '@vkontakte/vkjs';
import { useAdaptivityHasPointer } from '../../hooks/useAdaptivityHasPointer';
import { useDirection } from '../../hooks/useDirection';
import { useEventListener } from '../../hooks/useEventListener';
import { useExternRef } from '../../hooks/useExternRef';
import { easeInOutSine } from '../../lib/fx';
import type { HasRef, HTMLAttributesWithRootRef } from '../../types';
Expand Down Expand Up @@ -233,44 +232,33 @@ export const HorizontalScroll = ({
}
}, [showArrows, hasPointer, scrollerRef, setCanScrollStart, setCanScrollEnd]);

const scrollEvent = useEventListener('scroll', calculateArrowsVisibility);
React.useEffect(
function addScrollerRefToScrollEvent() {
if (!scrollerRef.current) {
return noop;
}
React.useEffect(calculateArrowsVisibility, [calculateArrowsVisibility, children]);

scrollEvent.add(scrollerRef.current);
return scrollEvent.remove;
const _onWheel = React.useCallback(
(e: React.WheelEvent) => {
scrollerRef.current!.scrollBy({ left: e.deltaX + e.deltaY, behavior: 'auto' });
},
[scrollEvent, scrollerRef],
[scrollerRef],
);

React.useEffect(calculateArrowsVisibility, [calculateArrowsVisibility, children]);

/**
* Прокрутка с помощью любого колеса мыши
*/
const onwheel = React.useCallback(
(e: WheelEvent) => {
scrollerRef.current!.scrollBy({ left: e.deltaX + e.deltaY, behavior: 'auto' });
const onScrollWheel = React.useCallback(
(e: React.WheelEvent) => {
_onWheel(e);
e.preventDefault();
},
[scrollerRef],
[_onWheel],
);

const wheelEvent = useEventListener('wheel', onwheel);
React.useEffect(
function addScrollerRefToWheelEvent() {
if (!scrollerRef.current || !scrollOnAnyWheel) {
return noop;
const onArrowWheel = React.useCallback(
(e: React.WheelEvent) => {
if (e.deltaX || (e.deltaY && scrollOnAnyWheel)) {
_onWheel(e);
}

wheelEvent.add(scrollerRef.current);

return wheelEvent.remove;
},
[wheelEvent, scrollerRef, scrollOnAnyWheel],
[_onWheel, scrollOnAnyWheel],
);

return (
Expand All @@ -293,6 +281,7 @@ export const HorizontalScroll = ({
tabIndex={-1}
className={classNames(styles.arrow, styles.arrowLeft)}
onClick={scrollToLeft}
onWheel={onArrowWheel}
/>
)}
{showArrows && (hasPointer || hasPointer === undefined) && canScrollRight && (
Expand All @@ -305,9 +294,15 @@ export const HorizontalScroll = ({
tabIndex={-1}
className={classNames(styles.arrow, styles.arrowRight)}
onClick={scrollToRight}
onWheel={onArrowWheel}
/>
)}
<div className={styles.in} ref={scrollerRef}>
<div
className={styles.in}
ref={scrollerRef}
onScroll={calculateArrowsVisibility}
onWheel={scrollOnAnyWheel ? onScrollWheel : undefined}
>
<div className={styles.inWrapper}>{children}</div>
</div>
</RootComponent>
Expand Down

0 comments on commit b661694

Please sign in to comment.