diff --git a/packages/vkui/src/components/BaseGallery/BaseGallery.tsx b/packages/vkui/src/components/BaseGallery/BaseGallery.tsx index 1781d3d838..33b98a313f 100644 --- a/packages/vkui/src/components/BaseGallery/BaseGallery.tsx +++ b/packages/vkui/src/components/BaseGallery/BaseGallery.tsx @@ -141,6 +141,13 @@ export const BaseGallery = ({ localSlides.length <= layoutState.current.slides.length || layoutState.current.slides[slideIndex]?.coordX !== localSlides[slideIndex]?.coordX; + const currentSlideOffsetOnCenterAlignment = + (localContainerWidth - (localSlides[slideIndex]?.width ?? 0)) / 2; + const isFullyVisible = + align === 'center' + ? localLayerWidth + currentSlideOffsetOnCenterAlignment <= localContainerWidth + : localLayerWidth <= localContainerWidth; + layoutState.current = { containerWidth: localContainerWidth, viewportOffsetWidth: localViewportOffsetWidth, @@ -159,7 +166,7 @@ export const BaseGallery = ({ align, }), slides: localSlides, - isFullyVisible: localLayerWidth <= localContainerWidth, + isFullyVisible, }; setShiftState((prevState) => ({ diff --git a/packages/vkui/src/components/Gallery/Gallery.test.tsx b/packages/vkui/src/components/Gallery/Gallery.test.tsx index 3e1b11b1e3..f98dc35424 100644 --- a/packages/vkui/src/components/Gallery/Gallery.test.tsx +++ b/packages/vkui/src/components/Gallery/Gallery.test.tsx @@ -73,13 +73,14 @@ const setup = ({ looped, containerWidth: defaultContainerWidth, isCustomSlideWidth = false, - viewPortWidth, + viewPortWidth: defaultViewPortWidth, align, onChange, onNext, onPrev, onDragStart, onDragEnd, + numberOfSlides = 5, }: { defaultSlideIndex: number; looped: boolean; @@ -87,6 +88,7 @@ const setup = ({ isCustomSlideWidth?: boolean; containerWidth: number; viewPortWidth: number; + numberOfSlides?: number; align?: AlignType; onChange: VoidFunction; onNext?: VoidFunction; @@ -99,6 +101,7 @@ const setup = ({ let layerTransform = ''; let viewPort: HTMLDivElement; let containerWidth = defaultContainerWidth; + let viewPortWidth = defaultViewPortWidth; const mockContainerData = (element: HTMLDivElement) => { if (!element) { @@ -161,21 +164,15 @@ const setup = ({ getRootRef={mockContainerData} getRef={mockViewportData} > - mockSlideData(e, 0)}> - 1 - - mockSlideData(e, 1)}> - 2 - - mockSlideData(e, 2)}> - 3 - - mockSlideData(e, 3)}> - 4 - - mockSlideData(e, 4)}> - 5 - + {Array.from({ length: numberOfSlides }).map((_v, index) => ( + mockSlideData(e, index)} + > + {index + 1} + + ))} ); @@ -200,6 +197,9 @@ const setup = ({ set containerWidth(newWidth: number) { containerWidth = newWidth; }, + set viewPortWidth(newWidth: number) { + viewPortWidth = newWidth; + }, }; }; @@ -640,4 +640,77 @@ describe('Gallery', () => { process.env.NODE_ENV = 'test'; }); }); + + it('checks gallery arrows and navigation in center alignment', () => { + const onChange = jest.fn(); + const onDragStart = jest.fn(); + const onDragEnd = jest.fn(); + + // в контейнере недостаточно места для + // двух слайдов с выравниванием по центру + // поэтому мы показываем кнопки и позволяем drag + const mockedData = setup({ + numberOfSlides: 2, + defaultSlideIndex: 2, + slideWidth: 180, + containerWidth: 300, + viewPortWidth: 300, + align: 'center', + looped: false, + onDragStart, + onDragEnd, + onChange, + }); + const { + component: { container }, + rerender, + } = mockedData; + + checkActiveSlide(container, 1); + mockedData.component.debug(); + expect(Array.from(container.getElementsByClassName(styles['BaseGallery__arrow']))).toHaveLength( + 1, + ); + + simulateDrag(mockedData.viewPort, [150, 0]); + + expect(onDragStart).toHaveBeenCalledTimes(1); + expect(onDragEnd).toHaveBeenCalledTimes(1); + + // это пограничное состояние при котором слайды ещё + // не помещаются в контейнер, + // при ширине контейнера 540 они уже будут влезать + mockedData.containerWidth = 539; + mockedData.viewPortWidth = 539; + onDragStart.mockClear(); + onDragEnd.mockClear(); + + rerender({ slideIndex: 2 }); + + expect(Array.from(container.getElementsByClassName(styles['BaseGallery__arrow']))).toHaveLength( + 1, + ); + + simulateDrag(mockedData.viewPort, [150, 0]); + + expect(onDragStart).toHaveBeenCalledTimes(1); + expect(onDragEnd).toHaveBeenCalledTimes(1); + + // слайды полностью помещаются, поэтому мы отключаем drag и не показываем стрелочки + mockedData.containerWidth = 540; + mockedData.viewPortWidth = 540; + onDragStart.mockClear(); + onDragEnd.mockClear(); + + rerender({ slideIndex: 2 }); + + expect(Array.from(container.getElementsByClassName(styles['BaseGallery__arrow']))).toHaveLength( + 0, + ); + + simulateDrag(mockedData.viewPort, [150, 0]); + + expect(onDragStart).not.toHaveBeenCalled(); + expect(onDragEnd).not.toHaveBeenCalled(); + }); });