diff --git a/packages/vkui/src/components/CardScroll/CardScroll.e2e-playground.tsx b/packages/vkui/src/components/CardScroll/CardScroll.e2e-playground.tsx index f295b6903b..3d3dab24a4 100644 --- a/packages/vkui/src/components/CardScroll/CardScroll.e2e-playground.tsx +++ b/packages/vkui/src/components/CardScroll/CardScroll.e2e-playground.tsx @@ -24,6 +24,10 @@ export const CardScrollPlayground = (props: ComponentPlaygroundProps) => { { padding: [false], }, + { + showArrows: ['always'], + $direction: 'rtl', + }, ]} > {(props: CardScrollProps) => {items}} diff --git a/packages/vkui/src/components/CardScroll/CardScroll.test.tsx b/packages/vkui/src/components/CardScroll/CardScroll.test.tsx index 88c06d0a29..9a52debf84 100644 --- a/packages/vkui/src/components/CardScroll/CardScroll.test.tsx +++ b/packages/vkui/src/components/CardScroll/CardScroll.test.tsx @@ -1,5 +1,6 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { baselineComponent } from '../../testing/utils'; +import { DirectionProvider } from '../DirectionProvider/DirectionProvider'; import { CardScroll } from './CardScroll'; import styles from './CardScroll.module.css'; import horizontalScrollStyles from '../HorizontalScroll/HorizontalScroll.module.css'; @@ -24,18 +25,9 @@ const setupHorizontalScrollData = (element: HTMLElement, startScrollLeft = 0) => }; }; -const mockCardScrollData = (container: HTMLElement, cardsCount: number, defaultScrollLeft = 50) => { +const mockCardScrollData = (cardsCount: number, defaultScrollLeft = 50, isRtl = false) => { const startOffsetLeft = 12; - new Array(cardsCount).fill(0).forEach((_, index) => { - const width = 400; - const gap = 8; - const card = screen.getByTestId(`card-${index}`); - - jest - .spyOn(card, 'offsetLeft', 'get') - .mockImplementation(() => startOffsetLeft + index * (width + gap)); - jest.spyOn(card, 'offsetWidth', 'get').mockImplementation(() => width); - }); + const containerWidth = 1009; const originalGetComputedStyle = window.getComputedStyle; @@ -44,7 +36,7 @@ const mockCardScrollData = (container: HTMLElement, cardsCount: number, defaultS .mockImplementation((e) => { return { ...originalGetComputedStyle(e), - marginRight: '8px', + marginInlineEnd: '8px', getPropertyValue: (property: string) => { if (property === '--vkui_internal--CardScroll_horizontal_padding') { return '12px'; @@ -54,14 +46,46 @@ const mockCardScrollData = (container: HTMLElement, cardsCount: number, defaultS }; }); + const mockCard = (card: HTMLElement, index: number) => { + const width = 400; + const gap = 8; + + const offsetLeft = startOffsetLeft + index * (width + gap); + const offset = isRtl ? containerWidth - offsetLeft - width : offsetLeft; + + jest.spyOn(card, 'offsetLeft', 'get').mockImplementation(() => offset); + jest.spyOn(card, 'offsetWidth', 'get').mockImplementation(() => width); + }; + + const { container } = render( + + + {Array.from({ length: cardsCount }).map((_, index) => ( +
{ + if (element) { + mockCard(element, index); + } + }} + >
+ ))} +
+
, + ); + const cardScrollContainer = container.getElementsByClassName(styles.in)[0] as HTMLDivElement; - jest.spyOn(cardScrollContainer, 'offsetWidth', 'get').mockImplementation(() => 1009); + jest.spyOn(cardScrollContainer, 'offsetWidth', 'get').mockImplementation(() => containerWidth); const horizontalScroll = container.getElementsByClassName( horizontalScrollStyles.in, )[0] as HTMLDivElement; return { - horizontalScrollData: setupHorizontalScrollData(horizontalScroll, defaultScrollLeft), + horizontalScrollData: setupHorizontalScrollData( + horizontalScroll, + defaultScrollLeft * (isRtl ? -1 : 1), + ), horizontalScroll, mocksRestore: () => { [getComputedStyleInstance].forEach((mock) => mock.mockRestore()); @@ -72,21 +96,14 @@ const mockCardScrollData = (container: HTMLElement, cardsCount: number, defaultS type PrepareDataParams = { defaultScrollLeft?: number; cardsCount?: number; + isRtl?: boolean; }; -const setup = ({ defaultScrollLeft = 50, cardsCount = 6 }: PrepareDataParams) => { - const { container } = render( - - {new Array(cardsCount).fill(0).map((_, index) => ( -
- ))} -
, - ); - +const setup = ({ defaultScrollLeft = 50, cardsCount = 6, isRtl = false }: PrepareDataParams) => { const { horizontalScrollData, horizontalScroll, mocksRestore } = mockCardScrollData( - container, cardsCount, defaultScrollLeft, + isRtl, ); fireEvent.mouseEnter(horizontalScroll); @@ -163,4 +180,57 @@ describe('CardScroll', () => { }); mocksRestore(); }); + + describe('check rtl working', () => { + it('check scroll by click arrow prev', async () => { + const { horizontalScrollData, mocksRestore } = setup({ + defaultScrollLeft: 1470, + isRtl: true, + }); + + const arrowPrev = screen.getByTestId('ScrollArrowLeft'); + + fireEvent.click(arrowPrev); + await waitFor(() => { + expect(horizontalScrollData.scrollLeft).toBe(-639); + }); + + fireEvent.click(arrowPrev); + await waitFor(() => { + expect(horizontalScrollData.scrollLeft).toBe(0); + }); + + fireEvent.click(arrowPrev); + await waitFor(() => { + expect(horizontalScrollData.scrollLeft).toBe(0); + }); + + mocksRestore(); + }); + + it('check scroll by click arrow next', async () => { + const { horizontalScrollData, mocksRestore } = setup({ + isRtl: true, + }); + + const arrowNext = screen.getByTestId('ScrollArrowRight'); + + fireEvent.click(arrowNext); + await waitFor(() => { + expect(horizontalScrollData.scrollLeft).toBe(-816); + }); + + fireEvent.click(arrowNext); + await waitFor(() => { + expect(horizontalScrollData.scrollLeft).toBe(-1477); + }); + + fireEvent.click(arrowNext); + await waitFor(() => { + expect(horizontalScrollData.scrollLeft).toBe(-1477); + }); + + mocksRestore(); + }); + }); }); diff --git a/packages/vkui/src/components/CardScroll/CardScroll.tsx b/packages/vkui/src/components/CardScroll/CardScroll.tsx index 5c94358a0d..f7710ec02d 100644 --- a/packages/vkui/src/components/CardScroll/CardScroll.tsx +++ b/packages/vkui/src/components/CardScroll/CardScroll.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; +import { useConfigDirection } from '../../hooks/useConfigDirection'; import { useDOM } from '../../lib/dom'; import type { HasComponent, HTMLAttributesWithRootRef } from '../../types'; import { HorizontalScroll, type HorizontalScrollProps } from '../HorizontalScroll/HorizontalScroll'; @@ -46,6 +47,7 @@ export const CardScroll = ({ ...restProps }: CardScrollProps): React.ReactNode => { const refContainer = React.useRef(null); + const direction = useConfigDirection(); const { window } = useDOM(); @@ -57,18 +59,33 @@ export const CardScroll = ({ ); }; + const slideOffsetFromStart = (slide: HTMLElement) => { + const containerWidth = refContainer.current?.offsetWidth || 0; + return direction === 'rtl' + ? containerWidth - slide.offsetLeft - slide.offsetWidth + : slide.offsetLeft; + }; + function getScrollToLeft(offset: number): number { if (!refContainer.current) { return offset; } const containerWidth = refContainer.current.offsetWidth; + + const getMarginEnd = (el: HTMLElement) => { + const computedStyles = window!.getComputedStyle(el); + return ( + parseInt(computedStyles.marginInlineEnd) || + (direction === 'rtl' + ? parseInt(computedStyles.marginLeft) + : parseInt(computedStyles.marginRight)) || + 0 + ); + }; + const slideIndex = ([...refContainer.current.children] as HTMLElement[]).findIndex( (el: HTMLElement) => - el.offsetLeft + - el.offsetWidth + - parseInt(window!.getComputedStyle(el).marginRight) - - offset >= - 0, + slideOffsetFromStart(el) + el.offsetWidth + getMarginEnd(el) - offset >= 0, ); if (slideIndex === -1) { @@ -77,7 +94,7 @@ export const CardScroll = ({ const slide = refContainer.current.children[slideIndex] as HTMLElement; const padding = getPadding(refContainer.current); - const scrollTo = slide.offsetLeft - (containerWidth - slide.offsetWidth) + padding; + const scrollTo = slideOffsetFromStart(slide) - (containerWidth - slide.offsetWidth) + padding; if (scrollTo <= 2 * padding) { return 0; @@ -90,19 +107,17 @@ export const CardScroll = ({ if (!refContainer.current) { return offset; } - const containerWidth = refContainer.current.offsetWidth; - const slide = Array.prototype.find.call( - refContainer.current.children, - (el: HTMLElement) => el.offsetLeft + el.offsetWidth - offset > containerWidth, - ) as HTMLElement; + const slide = Array.prototype.find.call(refContainer.current.children, (el: HTMLElement) => { + return slideOffsetFromStart(el) + el.offsetWidth - offset > containerWidth; + }) as HTMLElement; if (!slide) { return offset; } const padding = getPadding(refContainer.current); - return slide.offsetLeft - padding; + return slideOffsetFromStart(slide) - padding; } return ( diff --git a/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-android-chromium-dark-1-snap.png b/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-android-chromium-dark-1-snap.png index 599c76b8c0..9e2a1ec164 100644 --- a/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-android-chromium-dark-1-snap.png +++ b/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-android-chromium-dark-1-snap.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ec85749601405bc1b206ed0a9b8b8bddaeb9f0889cbe6bedf090471bf6d41222 -size 19495 +oid sha256:1630834b67d8b63be4828bf8d79c4df93d96858bd94280607abf8a9886e3585f +size 22393 diff --git a/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-android-chromium-light-1-snap.png b/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-android-chromium-light-1-snap.png index f0f0c2359e..3d7391bd6f 100644 --- a/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-android-chromium-light-1-snap.png +++ b/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-android-chromium-light-1-snap.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:62c8c019a94f25e63886ba53127c3198608cb95bad9f6b327af70f5ea8714e51 -size 17747 +oid sha256:973b6115366ba0c9943f5686281780de1d9ce0d83b592cf04d7cc08da60287de +size 20396 diff --git a/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-ios-webkit-dark-1-snap.png b/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-ios-webkit-dark-1-snap.png index be10a1ae5b..728f04831f 100644 --- a/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-ios-webkit-dark-1-snap.png +++ b/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-ios-webkit-dark-1-snap.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:49ce0361428994720bf9b2698f3203734913b5f04ca12420862709158fb9e2b3 -size 30023 +oid sha256:e94df940bea52e8a52c898c8bdf1baf7c3d08e81e7e7daf2a08fa70af4771c00 +size 34865 diff --git a/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-ios-webkit-light-1-snap.png b/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-ios-webkit-light-1-snap.png index 2b3d8532a2..87dc01a744 100644 --- a/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-ios-webkit-light-1-snap.png +++ b/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-ios-webkit-light-1-snap.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:675c7099bfcfe01c7d93a35a4930227a0943d5a6352572b7df29bd0d34d63b90 -size 28194 +oid sha256:b50fe80ebd4d04f2986328d2423dfee7ee2a764ea453e44d7c4f671aa73b97ff +size 32798 diff --git a/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-chromium-dark-1-snap.png b/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-chromium-dark-1-snap.png index e5880914ea..8dfd766276 100644 --- a/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-chromium-dark-1-snap.png +++ b/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-chromium-dark-1-snap.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fac5e805f1f9dd90f05df6e94d9d48b65524a8fe2e52a4525a6906df8aac50de -size 20348 +oid sha256:70a1772ae1f78068b994f3debd2c7bd374b2deb48632e0f97697f4f0b8107708 +size 24718 diff --git a/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-chromium-light-1-snap.png b/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-chromium-light-1-snap.png index b23fdf948d..6b1521ac73 100644 --- a/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-chromium-light-1-snap.png +++ b/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-chromium-light-1-snap.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ecf4d3516c57c64042f9b77c852d436898767ef3d633a943308732e08ddf9efe -size 19484 +oid sha256:82d02971417c28902855305ea9030d96f3f17f099f7a0acc12509693b4f746e5 +size 23849 diff --git a/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-firefox-dark-1-snap.png b/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-firefox-dark-1-snap.png index 5d6a1dc9d9..358f500d8e 100644 --- a/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-firefox-dark-1-snap.png +++ b/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-firefox-dark-1-snap.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3ac21d8200cde3ae7f673fd88df330883ea54f5c943be8b66fb98ce96433b899 -size 30055 +oid sha256:99a521370746e845af5ff7392cb69c691bf1871c4198d269c5bfde2e9094ba4e +size 36079 diff --git a/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-firefox-light-1-snap.png b/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-firefox-light-1-snap.png index 3d110ff043..71a988fbd0 100644 --- a/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-firefox-light-1-snap.png +++ b/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-firefox-light-1-snap.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c01476cb75a3aebfdf2540bcb59ae1e368624718382627c545ea8d4f84e7f836 -size 30525 +oid sha256:c9a2f9630ce01de04aceae846800a5d81c199eaefc2be2b7847057911862e7ce +size 37227 diff --git a/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-webkit-dark-1-snap.png b/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-webkit-dark-1-snap.png index c53064e972..9460c39232 100644 --- a/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-webkit-dark-1-snap.png +++ b/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-webkit-dark-1-snap.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:176224543eb2bc04efdb357e56e00fafbbf29c61e76a9a2f0ec3623dc8427264 -size 29376 +oid sha256:0f65cc93aa0bf9d927bf0f21cd91f58184d158aac2e423b16dc1cb2b96a76c69 +size 35339 diff --git a/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-webkit-light-1-snap.png b/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-webkit-light-1-snap.png index e9f350d1bc..8d1fa41fa4 100644 --- a/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-webkit-light-1-snap.png +++ b/packages/vkui/src/components/CardScroll/__image_snapshots__/cardscroll-vkcom-webkit-light-1-snap.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d2b729040484d03940effef4b3371cb168ab896339493fbf38a1dd699e0b0c3a -size 28977 +oid sha256:afc6f23b3552cacf89ab13dc93d7553b0c2e2555cf81701f40cb25536831b33f +size 35308 diff --git a/packages/vkui/src/components/HorizontalScroll/HorizontalScroll.e2e-playground.tsx b/packages/vkui/src/components/HorizontalScroll/HorizontalScroll.e2e-playground.tsx index 7fd7a6f266..6d6f133071 100644 --- a/packages/vkui/src/components/HorizontalScroll/HorizontalScroll.e2e-playground.tsx +++ b/packages/vkui/src/components/HorizontalScroll/HorizontalScroll.e2e-playground.tsx @@ -29,6 +29,11 @@ export const HorizontalScrollMobilePlayground = (props: ComponentPlaygroundProps arrowSize: ['s', 'm'], children: [items], }, + { + showArrows: ['always'], + $direction: 'rtl', + children: [items], + }, ]} > {baseRender} @@ -47,6 +52,11 @@ export const HorizontalScrollSmallTabletPlayground = (props: ComponentPlayground arrowOffsetY: [-10], children: [items], }, + { + showArrows: ['always'], + dir: ['rtl'], + children: [items], + }, ]} > {baseRender} diff --git a/packages/vkui/src/components/HorizontalScroll/HorizontalScroll.module.css b/packages/vkui/src/components/HorizontalScroll/HorizontalScroll.module.css index cb0f261691..b0da8ea02f 100644 --- a/packages/vkui/src/components/HorizontalScroll/HorizontalScroll.module.css +++ b/packages/vkui/src/components/HorizontalScroll/HorizontalScroll.module.css @@ -7,6 +7,12 @@ */ overflow-x: hidden; isolation: isolate; + + --vkui_internal--HorizontalScroll_shift_direction: 1; +} + +.rtl { + --vkui_internal--HorizontalScroll_shift_direction: -1; } .in { @@ -48,11 +54,11 @@ } .arrowLeft:hover ~ .in .inWrapper { - transform: translateX(8px); + transform: translateX(calc(8px * var(--vkui_internal--HorizontalScroll_shift_direction))); } .arrowRight:hover ~ .in .inWrapper { - transform: translateX(-8px); + transform: translateX(calc(-8px * var(--vkui_internal--HorizontalScroll_shift_direction))); } /** diff --git a/packages/vkui/src/components/HorizontalScroll/HorizontalScroll.test.tsx b/packages/vkui/src/components/HorizontalScroll/HorizontalScroll.test.tsx index e82b75b188..4aa2fc0ec3 100644 --- a/packages/vkui/src/components/HorizontalScroll/HorizontalScroll.test.tsx +++ b/packages/vkui/src/components/HorizontalScroll/HorizontalScroll.test.tsx @@ -4,6 +4,7 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { noop } from '@vkontakte/vkjs'; import { baselineComponent, userEvent } from '../../testing/utils'; import { AdaptivityProvider } from '../AdaptivityProvider/AdaptivityProvider'; +import { DirectionProvider } from '../DirectionProvider/DirectionProvider'; import { HorizontalScroll } from './HorizontalScroll'; const setup = (element: HTMLElement, startScrollLeft = 0) => { @@ -190,6 +191,49 @@ describe('HorizontalScroll', () => { expect(mockedData.scrollLeft).toBe(200); }); }); + + describe('check rtl working', () => { + it('click on arrows should change scrollLeft', async () => { + const ref: React.RefObject = { + current: null, + }; + render( + + +
+ + , + ); + + const mockedData = setup(ref.current!); + expect(mockedData.scrollLeft).toBe(0); + + fireEvent.mouseEnter(screen.getByTestId('horizontal-scroll')); + + const arrowNext = screen.getByTestId('next-scroll-arrow'); + fireEvent.click(arrowNext); + fireEvent.click(arrowNext); + + await waitFor(() => { + expect(mockedData.scrollLeft).toBe(-300); + }); + + fireEvent.mouseEnter(screen.getByTestId('horizontal-scroll')); + + const arrowPrev = screen.getByTestId('prev-scroll-arrow'); + fireEvent.click(arrowPrev); + fireEvent.click(arrowPrev); + + await waitFor(() => { + expect(mockedData.scrollLeft).toBe(0); + }); + }); + }); }); function mockRef(element: HTMLDivElement) { diff --git a/packages/vkui/src/components/HorizontalScroll/HorizontalScroll.tsx b/packages/vkui/src/components/HorizontalScroll/HorizontalScroll.tsx index 8bb09f364f..0f188c3061 100644 --- a/packages/vkui/src/components/HorizontalScroll/HorizontalScroll.tsx +++ b/packages/vkui/src/components/HorizontalScroll/HorizontalScroll.tsx @@ -132,8 +132,15 @@ function doScroll({ const extremeScrollLeft = (textDirection === 'ltr' ? 1 : -1) * (initialScrollWidth - scrollElement.offsetWidth); - let startScrollLeft = roundUpElementScrollLeft(scrollElement); - let endScrollLeft = getScrollPosition(startScrollLeft); + const startScrollLeft = roundUpElementScrollLeft(scrollElement); + const remappedStartScrollLeft = startScrollLeft * (textDirection === 'rtl' ? -1 : 1); + + let endScrollLeft = getScrollPosition(remappedStartScrollLeft); + + const diff = endScrollLeft - remappedStartScrollLeft; + if (textDirection === 'rtl') { + endScrollLeft = startScrollLeft - diff; + } onScrollStart(); @@ -196,11 +203,10 @@ export const HorizontalScroll = ({ contentWrapperClassName, ...restProps }: HorizontalScrollProps): React.ReactNode => { - const [canScrollLeft, setCanScrollLeft] = React.useState(false); - const [canScrollRight, setCanScrollRight] = React.useState(false); + const [canScrollStart, setCanScrollStart] = React.useState(false); + const [canScrollEnd, setCanScrollEnd] = React.useState(false); const direction = useConfigDirection(); - const setCanScrollStart = direction === 'ltr' ? setCanScrollLeft : setCanScrollRight; - const setCanScrollEnd = direction === 'ltr' ? setCanScrollRight : setCanScrollLeft; + const isRtl = direction === 'rtl'; const isCustomScrollingRef = React.useRef(false); @@ -234,13 +240,13 @@ export const HorizontalScroll = ({ [scrollerRef, scrollAnimationDuration, direction, setCanScrollEnd], ); - const scrollToLeft = React.useCallback(() => { + const scrollToStart = React.useCallback(() => { const getScrollPosition = getScrollToLeft ?? ((i: number) => i - scrollerRef.current!.offsetWidth); scrollTo(getScrollPosition); }, [getScrollToLeft, scrollTo, scrollerRef]); - const scrollToRight = React.useCallback(() => { + const scrollToEnd = React.useCallback(() => { const getScrollPosition = getScrollToRight ?? ((i: number) => i + scrollerRef.current!.offsetWidth); scrollTo(getScrollPosition); @@ -249,14 +255,15 @@ export const HorizontalScroll = ({ const calculateArrowsVisibility = React.useCallback(() => { if (showArrows && hasPointer && scrollerRef.current && !isCustomScrollingRef.current) { const scrollElement = scrollerRef.current; + const scrollLeft = scrollElement.scrollLeft; - setCanScrollStart(scrollElement.scrollLeft !== 0); + setCanScrollStart(isRtl ? scrollLeft < 0 : scrollLeft > 0); setCanScrollEnd( Math.abs(roundUpElementScrollLeft(scrollElement)) + scrollElement.offsetWidth < scrollElement.scrollWidth, ); } - }, [showArrows, hasPointer, scrollerRef, setCanScrollStart, setCanScrollEnd]); + }, [showArrows, hasPointer, scrollerRef, isRtl]); React.useEffect(calculateArrowsVisibility, [calculateArrowsVisibility, children]); @@ -300,10 +307,11 @@ export const HorizontalScroll = ({ styles.host, 'vkuiInternalHorizontalScroll', showArrows === 'always' && styles.withConstArrows, + isRtl && styles.rtl, )} onMouseEnter={calculateArrowsVisibility} > - {showArrows && (hasPointer || hasPointer === undefined) && canScrollLeft && ( + {showArrows && (hasPointer || hasPointer === undefined) && canScrollStart && ( )} - {showArrows && (hasPointer || hasPointer === undefined) && canScrollRight && ( + {showArrows && (hasPointer || hasPointer === undefined) && canScrollEnd && ( )}
diff --git a/packages/vkui/src/components/HorizontalScroll/__image_snapshots__/horizontalscroll-viewwidth-mobile-haspointer-false-android-chromium-dark-1-snap.png b/packages/vkui/src/components/HorizontalScroll/__image_snapshots__/horizontalscroll-viewwidth-mobile-haspointer-false-android-chromium-dark-1-snap.png index d72b3c9de5..419188d37f 100644 --- a/packages/vkui/src/components/HorizontalScroll/__image_snapshots__/horizontalscroll-viewwidth-mobile-haspointer-false-android-chromium-dark-1-snap.png +++ b/packages/vkui/src/components/HorizontalScroll/__image_snapshots__/horizontalscroll-viewwidth-mobile-haspointer-false-android-chromium-dark-1-snap.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:25ed522e95d972a1932dbb746a09ef48183e8bd90c372183fac5f34786cd1e58 -size 14271 +oid sha256:33666e4bce09a5b3e02ef7a5a3e89c8eff9bf859813dda9a2316892fb76e951c +size 20701 diff --git a/packages/vkui/src/components/HorizontalScroll/__image_snapshots__/horizontalscroll-viewwidth-mobile-haspointer-false-android-chromium-light-1-snap.png b/packages/vkui/src/components/HorizontalScroll/__image_snapshots__/horizontalscroll-viewwidth-mobile-haspointer-false-android-chromium-light-1-snap.png index 5e5cae6b8b..1527c8ef08 100644 --- a/packages/vkui/src/components/HorizontalScroll/__image_snapshots__/horizontalscroll-viewwidth-mobile-haspointer-false-android-chromium-light-1-snap.png +++ b/packages/vkui/src/components/HorizontalScroll/__image_snapshots__/horizontalscroll-viewwidth-mobile-haspointer-false-android-chromium-light-1-snap.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:307ea2ad4b2856b0f74bd896785507197e42c9357cda4db304563b7423e097b1 -size 13377 +oid sha256:82d705249d789d8685aed158615b1b763ec35ad706ec5fa063a5d6298b17d488 +size 19432 diff --git a/packages/vkui/src/components/HorizontalScroll/__image_snapshots__/horizontalscroll-viewwidth-small-tablet-haspointer-true-android-chromium-dark-1-snap.png b/packages/vkui/src/components/HorizontalScroll/__image_snapshots__/horizontalscroll-viewwidth-small-tablet-haspointer-true-android-chromium-dark-1-snap.png index 29910604fe..372a3fdd45 100644 --- a/packages/vkui/src/components/HorizontalScroll/__image_snapshots__/horizontalscroll-viewwidth-small-tablet-haspointer-true-android-chromium-dark-1-snap.png +++ b/packages/vkui/src/components/HorizontalScroll/__image_snapshots__/horizontalscroll-viewwidth-small-tablet-haspointer-true-android-chromium-dark-1-snap.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eaf0b39c4a9b5e3db07ca9e108131cdec5eddb1795891801fbb43203b47b5e6b -size 42673 +oid sha256:0b6eed74d8789c69a691827afa34e75a319fa5bc7007cbe2fb6b83776818a00c +size 53264 diff --git a/packages/vkui/src/components/HorizontalScroll/__image_snapshots__/horizontalscroll-viewwidth-small-tablet-haspointer-true-android-chromium-light-1-snap.png b/packages/vkui/src/components/HorizontalScroll/__image_snapshots__/horizontalscroll-viewwidth-small-tablet-haspointer-true-android-chromium-light-1-snap.png index 97f58af078..42344775b1 100644 --- a/packages/vkui/src/components/HorizontalScroll/__image_snapshots__/horizontalscroll-viewwidth-small-tablet-haspointer-true-android-chromium-light-1-snap.png +++ b/packages/vkui/src/components/HorizontalScroll/__image_snapshots__/horizontalscroll-viewwidth-small-tablet-haspointer-true-android-chromium-light-1-snap.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e0c7a3fa2bda7039206ae625fc85da652654d704b31338b4c900fb003733f6a6 -size 41511 +oid sha256:7f5a2a29f78d03508e009921a8438030fb1cf8fee4e49f8453dd8bfab7625fc8 +size 51832