From 7febafaa5f0a4db30230e9ed0849d63cc35f1bce Mon Sep 17 00:00:00 2001 From: Tolu A Date: Mon, 8 Apr 2024 11:26:55 -0600 Subject: [PATCH] Bug fix for #819. --- .../fixtures/slidesToScroll-ltr.fixture.ts | 59 +++++++++++++++++++ .../fixtures/slidesToScroll-rtl.fixture.ts | 59 +++++++++++++++++++ .../slidesToScroll-vertical.fixture.ts | 58 ++++++++++++++++++ .../src/__tests__/slidesToScroll-ltr.test.ts | 47 ++++++++++++++- .../src/__tests__/slidesToScroll-rtl.test.ts | 51 +++++++++++++++- .../__tests__/slidesToScroll-vertical.test.ts | 51 +++++++++++++++- .../src/components/SlidesToScroll.ts | 4 +- 7 files changed, 324 insertions(+), 5 deletions(-) diff --git a/packages/embla-carousel/src/__tests__/fixtures/slidesToScroll-ltr.fixture.ts b/packages/embla-carousel/src/__tests__/fixtures/slidesToScroll-ltr.fixture.ts index 53b052bf..667fa3e3 100644 --- a/packages/embla-carousel/src/__tests__/fixtures/slidesToScroll-ltr.fixture.ts +++ b/packages/embla-carousel/src/__tests__/fixtures/slidesToScroll-ltr.fixture.ts @@ -163,3 +163,62 @@ export const FIXTURE_SLIDES_TO_SCROLL_LTR_2: TestElementDimensionsType = { value: 20 } } + +/* +Fixture 3 + +- Horizontal +- LTR +- No slide margins +- Slides are wider than viewport +*/ +export const FIXTURE_SLIDES_TO_SCROLL_LTR_3: TestElementDimensionsType = { + containerOffset: { + offsetWidth: 480, + offsetHeight: 190, + offsetTop: 0, + offsetLeft: 0 + }, + slideOffsets: [ + { + offsetWidth: 576, + offsetHeight: 190, + offsetTop: 0, + offsetLeft: 0 + }, + { + offsetWidth: 576, + offsetHeight: 190, + offsetTop: 0, + offsetLeft: 576 + }, + { + offsetWidth: 576, + offsetHeight: 190, + offsetTop: 0, + offsetLeft: 1152 + }, + { + offsetWidth: 576, + offsetHeight: 190, + offsetTop: 0, + offsetLeft: 1728 + }, + { + offsetWidth: 576, + offsetHeight: 190, + offsetTop: 0, + offsetLeft: 2304 + }, + { + offsetWidth: 576, + offsetHeight: 190, + offsetTop: 0, + offsetLeft: 2880 + } + ], + endMargin: { + property: 'marginRight', + value: 0 + } +} diff --git a/packages/embla-carousel/src/__tests__/fixtures/slidesToScroll-rtl.fixture.ts b/packages/embla-carousel/src/__tests__/fixtures/slidesToScroll-rtl.fixture.ts index 0bea0dd1..d9f824c1 100644 --- a/packages/embla-carousel/src/__tests__/fixtures/slidesToScroll-rtl.fixture.ts +++ b/packages/embla-carousel/src/__tests__/fixtures/slidesToScroll-rtl.fixture.ts @@ -163,3 +163,62 @@ export const FIXTURE_SLIDES_TO_SCROLL_RTL_2: TestElementDimensionsType = { value: 20 } } + +/* +Fixture 3 + +- Horizontal +- RTL +- No slide margins +- Slides are wider than viewport +*/ +export const FIXTURE_SLIDES_TO_SCROLL_RTL_3: TestElementDimensionsType = { + containerOffset: { + offsetWidth: 480, + offsetHeight: 190, + offsetTop: 0, + offsetLeft: 0 + }, + slideOffsets: [ + { + offsetWidth: 576, + offsetHeight: 190, + offsetTop: 0, + offsetLeft: -96 + }, + { + offsetWidth: 576, + offsetHeight: 190, + offsetTop: 0, + offsetLeft: -672 + }, + { + offsetWidth: 576, + offsetHeight: 190, + offsetTop: 0, + offsetLeft: -1248 + }, + { + offsetWidth: 576, + offsetHeight: 190, + offsetTop: 0, + offsetLeft: -1824 + }, + { + offsetWidth: 576, + offsetHeight: 190, + offsetTop: 0, + offsetLeft: -2400 + }, + { + offsetWidth: 576, + offsetHeight: 190, + offsetTop: 0, + offsetLeft: -2976 + } + ], + endMargin: { + property: 'marginLeft', + value: 0 + } +} diff --git a/packages/embla-carousel/src/__tests__/fixtures/slidesToScroll-vertical.fixture.ts b/packages/embla-carousel/src/__tests__/fixtures/slidesToScroll-vertical.fixture.ts index 9536f1ee..39401840 100644 --- a/packages/embla-carousel/src/__tests__/fixtures/slidesToScroll-vertical.fixture.ts +++ b/packages/embla-carousel/src/__tests__/fixtures/slidesToScroll-vertical.fixture.ts @@ -161,3 +161,61 @@ export const FIXTURE_SLIDES_TO_SCROLL_Y_2: TestElementDimensionsType = { value: 20 } } + +/* +Fixture 3 + +- Vertical +- No slide margins +- Slides are taller than viewport +*/ +export const FIXTURE_SLIDES_TO_SCROLL_Y_3: TestElementDimensionsType = { + containerOffset: { + offsetWidth: 480, + offsetHeight: 190, + offsetTop: 0, + offsetLeft: 0 + }, + slideOffsets: [ + { + offsetWidth: 480, + offsetHeight: 228, + offsetTop: 0, + offsetLeft: 0 + }, + { + offsetWidth: 480, + offsetHeight: 228, + offsetTop: 228, + offsetLeft: 0 + }, + { + offsetWidth: 480, + offsetHeight: 228, + offsetTop: 456, + offsetLeft: 0 + }, + { + offsetWidth: 480, + offsetHeight: 228, + offsetTop: 684, + offsetLeft: 0 + }, + { + offsetWidth: 480, + offsetHeight: 228, + offsetTop: 912, + offsetLeft: 0 + }, + { + offsetWidth: 480, + offsetHeight: 228, + offsetTop: 1140, + offsetLeft: 0 + } + ], + endMargin: { + property: 'marginBottom', + value: 0 + } +} diff --git a/packages/embla-carousel/src/__tests__/slidesToScroll-ltr.test.ts b/packages/embla-carousel/src/__tests__/slidesToScroll-ltr.test.ts index d374b9b6..e037c055 100644 --- a/packages/embla-carousel/src/__tests__/slidesToScroll-ltr.test.ts +++ b/packages/embla-carousel/src/__tests__/slidesToScroll-ltr.test.ts @@ -3,7 +3,8 @@ import { defaultOptions } from '../components/Options' import { mockTestElements } from './mocks' import { FIXTURE_SLIDES_TO_SCROLL_LTR_1, - FIXTURE_SLIDES_TO_SCROLL_LTR_2 + FIXTURE_SLIDES_TO_SCROLL_LTR_2, + FIXTURE_SLIDES_TO_SCROLL_LTR_3 } from './fixtures/slidesToScroll-ltr.fixture' const FIRST_SNAP_INDEX = 0 @@ -126,6 +127,50 @@ describe('➡️ SlidesToScroll - Horizontal LTR', () => { }) }) + describe('"auto" is correct for edge cases when slide width is greater than viewport and:', () => { + const emblaApi = EmblaCarousel( + mockTestElements(FIXTURE_SLIDES_TO_SCROLL_LTR_3) + ) + + beforeEach(() => { + emblaApi.reInit({ ...defaultOptions, slidesToScroll: 'auto' }) + }) + + test('LOOP:FALSE', () => { + const engine = emblaApi.internalEngine() + const expectedScrollSnaps = [0, -624, -1200, -1776, -2352, -2976] + + expect(engine.scrollSnaps).toEqual(expectedScrollSnaps) + expect(engine.location.get()).toBe(expectedScrollSnaps[FIRST_SNAP_INDEX]) + + expect(engine.slideRegistry).toEqual([[0], [1], [2], [3], [4], [5]]) + }) + + test('LOOP:FALSE and CONTAINSCROLL:FALSE', () => { + emblaApi.reInit({ containScroll: false }) + + const engine = emblaApi.internalEngine() + const expectedScrollSnaps = [-48, -624, -1200, -1776, -2352, -2928] + + expect(engine.scrollSnaps).toEqual(expectedScrollSnaps) + expect(engine.location.get()).toBe(expectedScrollSnaps[FIRST_SNAP_INDEX]) + + expect(engine.slideRegistry).toEqual([[0], [1], [2], [3], [4], [5]]) + }) + + test('LOOP:TRUE', () => { + emblaApi.reInit({ loop: true }) + + const engine = emblaApi.internalEngine() + const expectedScrollSnaps = [-48, -624, -1200, -1776, -2352, -2928] + + expect(engine.scrollSnaps).toEqual(expectedScrollSnaps) + expect(engine.location.get()).toBe(expectedScrollSnaps[FIRST_SNAP_INDEX]) + + expect(engine.slideRegistry).toEqual([[0], [1], [2], [3], [4], [5]]) + }) + }) + describe('"Custom number 2" is correct for slides WITHOUT MARGINS and:', () => { const emblaApi = EmblaCarousel( mockTestElements(FIXTURE_SLIDES_TO_SCROLL_LTR_1) diff --git a/packages/embla-carousel/src/__tests__/slidesToScroll-rtl.test.ts b/packages/embla-carousel/src/__tests__/slidesToScroll-rtl.test.ts index 7660e8f6..458f1ffe 100644 --- a/packages/embla-carousel/src/__tests__/slidesToScroll-rtl.test.ts +++ b/packages/embla-carousel/src/__tests__/slidesToScroll-rtl.test.ts @@ -3,7 +3,8 @@ import { defaultOptions } from '../components/Options' import { mockTestElements } from './mocks' import { FIXTURE_SLIDES_TO_SCROLL_RTL_1, - FIXTURE_SLIDES_TO_SCROLL_RTL_2 + FIXTURE_SLIDES_TO_SCROLL_RTL_2, + FIXTURE_SLIDES_TO_SCROLL_RTL_3 } from './fixtures/slidesToScroll-rtl.fixture' const FIRST_SNAP_INDEX = 0 @@ -135,6 +136,54 @@ describe('➡️ SlidesToScroll - Horizontal RTL', () => { }) }) + describe('"auto" is correct for edge cases when slide width is greater than viewport and:', () => { + const emblaApi = EmblaCarousel( + mockTestElements(FIXTURE_SLIDES_TO_SCROLL_RTL_3) + ) + + beforeEach(() => { + emblaApi.reInit({ + ...defaultOptions, + slidesToScroll: 'auto', + direction: 'rtl' + }) + }) + + test('LOOP:FALSE', () => { + const engine = emblaApi.internalEngine() + const expectedScrollSnaps = [0, -624, -1200, -1776, -2352, -2976] + + expect(engine.scrollSnaps).toEqual(expectedScrollSnaps) + expect(engine.location.get()).toBe(expectedScrollSnaps[FIRST_SNAP_INDEX]) + + expect(engine.slideRegistry).toEqual([[0], [1], [2], [3], [4], [5]]) + }) + + test('LOOP:FALSE and CONTAINSCROLL:FALSE', () => { + emblaApi.reInit({ containScroll: false }) + + const engine = emblaApi.internalEngine() + const expectedScrollSnaps = [-48, -624, -1200, -1776, -2352, -2928] + + expect(engine.scrollSnaps).toEqual(expectedScrollSnaps) + expect(engine.location.get()).toBe(expectedScrollSnaps[FIRST_SNAP_INDEX]) + + expect(engine.slideRegistry).toEqual([[0], [1], [2], [3], [4], [5]]) + }) + + test('LOOP:TRUE', () => { + emblaApi.reInit({ loop: true }) + + const engine = emblaApi.internalEngine() + const expectedScrollSnaps = [-48, -624, -1200, -1776, -2352, -2928] + + expect(engine.scrollSnaps).toEqual(expectedScrollSnaps) + expect(engine.location.get()).toBe(expectedScrollSnaps[FIRST_SNAP_INDEX]) + + expect(engine.slideRegistry).toEqual([[0], [1], [2], [3], [4], [5]]) + }) + }) + describe('"Custom number 2" is correct for slides WITHOUT MARGINS and:', () => { const emblaApi = EmblaCarousel( mockTestElements(FIXTURE_SLIDES_TO_SCROLL_RTL_1) diff --git a/packages/embla-carousel/src/__tests__/slidesToScroll-vertical.test.ts b/packages/embla-carousel/src/__tests__/slidesToScroll-vertical.test.ts index b67b33af..806360cc 100644 --- a/packages/embla-carousel/src/__tests__/slidesToScroll-vertical.test.ts +++ b/packages/embla-carousel/src/__tests__/slidesToScroll-vertical.test.ts @@ -3,7 +3,8 @@ import { defaultOptions } from '../components/Options' import { mockTestElements } from './mocks' import { FIXTURE_SLIDES_TO_SCROLL_Y_1, - FIXTURE_SLIDES_TO_SCROLL_Y_2 + FIXTURE_SLIDES_TO_SCROLL_Y_2, + FIXTURE_SLIDES_TO_SCROLL_Y_3 } from './fixtures/slidesToScroll-vertical.fixture' const FIRST_SNAP_INDEX = 0 @@ -127,6 +128,54 @@ describe('➡️ SlidesToScroll - Vertical', () => { }) }) + describe('"auto" is correct for edge cases when slide width is greater than viewport and:', () => { + const emblaApi = EmblaCarousel( + mockTestElements(FIXTURE_SLIDES_TO_SCROLL_Y_3) + ) + + beforeEach(() => { + emblaApi.reInit({ + ...defaultOptions, + slidesToScroll: 'auto', + axis: 'y' + }) + }) + + test('LOOP:FALSE', () => { + const engine = emblaApi.internalEngine() + const expectedScrollSnaps = [0, -247, -475, -703, -931, -1178] + + expect(engine.scrollSnaps).toEqual(expectedScrollSnaps) + expect(engine.location.get()).toBe(expectedScrollSnaps[FIRST_SNAP_INDEX]) + + expect(engine.slideRegistry).toEqual([[0], [1], [2], [3], [4], [5]]) + }) + + test('LOOP:FALSE and CONTAINSCROLL:FALSE', () => { + emblaApi.reInit({ containScroll: false }) + + const engine = emblaApi.internalEngine() + const expectedScrollSnaps = [-19, -247, -475, -703, -931, -1159] + + expect(engine.scrollSnaps).toEqual(expectedScrollSnaps) + expect(engine.location.get()).toBe(expectedScrollSnaps[FIRST_SNAP_INDEX]) + + expect(engine.slideRegistry).toEqual([[0], [1], [2], [3], [4], [5]]) + }) + + test('LOOP:TRUE', () => { + emblaApi.reInit({ loop: true }) + + const engine = emblaApi.internalEngine() + const expectedScrollSnaps = [-19, -247, -475, -703, -931, -1159] + + expect(engine.scrollSnaps).toEqual(expectedScrollSnaps) + expect(engine.location.get()).toBe(expectedScrollSnaps[FIRST_SNAP_INDEX]) + + expect(engine.slideRegistry).toEqual([[0], [1], [2], [3], [4], [5]]) + }) + }) + describe('"Custom number 2" is correct for slides WITHOUT MARGINS and:', () => { const emblaApi = EmblaCarousel( mockTestElements(FIXTURE_SLIDES_TO_SCROLL_Y_1) diff --git a/packages/embla-carousel/src/components/SlidesToScroll.ts b/packages/embla-carousel/src/components/SlidesToScroll.ts index a71e1687..aa81eee8 100644 --- a/packages/embla-carousel/src/components/SlidesToScroll.ts +++ b/packages/embla-carousel/src/components/SlidesToScroll.ts @@ -38,7 +38,7 @@ export function SlidesToScroll( if (!array.length) return [] return arrayKeys(array) - .reduce((groups: number[], rectB) => { + .reduce((groups: number[], rectB, index) => { const rectA = arrayLast(groups) || 0 const isFirst = rectA === 0 const isLast = rectB === arrayLastIndex(array) @@ -49,7 +49,7 @@ export function SlidesToScroll( const gapB = !loop && isLast ? direction(endGap) : 0 const chunkSize = mathAbs(edgeB - gapB - (edgeA + gapA)) - if (chunkSize > viewSize + pixelTolerance) groups.push(rectB) + if (index && chunkSize > viewSize + pixelTolerance) groups.push(rectB) if (isLast) groups.push(array.length) return groups }, [])