Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(Gallery): navigation doesn't work when align="center" and slides overflow just a little #7862

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion packages/vkui/src/components/BaseGallery/BaseGallery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,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,
Expand All @@ -161,7 +168,7 @@ export const BaseGallery = ({
align,
}),
slides: localSlides,
isFullyVisible: localLayerWidth <= localContainerWidth,
isFullyVisible,
};

setShiftState((prevState) => ({
Expand Down
98 changes: 82 additions & 16 deletions packages/vkui/src/components/Gallery/Gallery.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,22 @@ const setup = ({
looped,
containerWidth: defaultContainerWidth,
isCustomSlideWidth = false,
viewPortWidth,
viewPortWidth: defaultViewPortWidth,
align,
onChange,
onNext,
onPrev,
onDragStart,
onDragEnd,
numberOfSlides = 5,
}: {
defaultSlideIndex: number;
looped: boolean;
slideWidth: number;
isCustomSlideWidth?: boolean;
containerWidth: number;
viewPortWidth: number;
numberOfSlides?: number;
align?: AlignType;
onChange: VoidFunction;
onNext?: VoidFunction;
Expand All @@ -99,6 +101,7 @@ const setup = ({
let layerTransform = '';
let viewPort: HTMLDivElement;
let containerWidth = defaultContainerWidth;
let viewPortWidth = defaultViewPortWidth;

const mockContainerData = (element: HTMLDivElement) => {
if (!element) {
Expand Down Expand Up @@ -161,21 +164,15 @@ const setup = ({
getRootRef={mockContainerData}
getRef={mockViewportData}
>
<Slide data-testid="slide-1" getRef={(e: HTMLDivElement) => mockSlideData(e, 0)}>
1
</Slide>
<Slide data-testid="slide-2" getRef={(e: HTMLDivElement) => mockSlideData(e, 1)}>
2
</Slide>
<Slide data-testid="slide-3" getRef={(e: HTMLDivElement) => mockSlideData(e, 2)}>
3
</Slide>
<Slide data-testid="slide-4" getRef={(e: HTMLDivElement) => mockSlideData(e, 3)}>
4
</Slide>
<Slide data-testid="slide-5" getRef={(e: HTMLDivElement) => mockSlideData(e, 4)}>
5
</Slide>
{Array.from({ length: numberOfSlides }).map((_v, index) => (
<Slide
key={index}
data-testid={`slide-${index + 1}`}
getRef={(e: HTMLDivElement) => mockSlideData(e, index)}
>
{index + 1}
</Slide>
))}
</Gallery>
);

Expand All @@ -200,6 +197,9 @@ const setup = ({
set containerWidth(newWidth: number) {
containerWidth = newWidth;
},
set viewPortWidth(newWidth: number) {
viewPortWidth = newWidth;
},
};
};

Expand Down Expand Up @@ -636,4 +636,70 @@ 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);
expect(Array.from(container.getElementsByClassName(styles.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.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.arrow))).toHaveLength(0);

simulateDrag(mockedData.viewPort, [150, 0]);

expect(onDragStart).not.toHaveBeenCalled();
expect(onDragEnd).not.toHaveBeenCalled();
});
});
Loading