diff --git a/src/components/Carousel/Carousel.svelte b/src/components/Carousel/Carousel.svelte index 4ab0c61..a6293ea 100644 --- a/src/components/Carousel/Carousel.svelte +++ b/src/components/Carousel/Carousel.svelte @@ -12,13 +12,20 @@ addResizeEventListener, removeResizeEventListener } from '../../utils/event' - import { getAdjacentIndexes } from '../../utils/page' + import { + getAdjacentIndexes, + getClones, + applyClones, + getPageSizes, + applyPageSizes, + getCurrentPageIndexWithoutClones, + getPagesCountWithoutClones, + getOneSideClonesCount, + } from '../../utils/page' import { get } from '../../utils/object' import { ProgressManager } from '../../utils/ProgressManager' import { wait } from '../../utils/interval' - const CLONES_COUNT = 2 - const dispatch = createEventDispatcher() const autoplayDirectionFnDescription = { @@ -101,7 +108,7 @@ if (typeof pageIndex !== 'number') { throw new Error('pageIndex should be a number') } - await showPage(pageIndex + Number(infinite), { animated }) + await showPage(pageIndex + oneSideClonesCount, { animated }) } export async function goToPrev(options) { @@ -115,26 +122,30 @@ } let store = createStore() + let oneSideClonesCount = getOneSideClonesCount({ + infinite, + }) + let currentPageIndex = 0 - $: originalCurrentPageIndex = getOriginalCurrentPageIndex(currentPageIndex, pagesCount, infinite) // index without cloenes - $: dispatch('pageChange', originalCurrentPageIndex) + $: currentPageIndexWithoutClones = getCurrentPageIndexWithoutClones({ + currentPageIndex, + pagesCount, + oneSideClonesCount, + infinite, + }) + $: dispatch('pageChange', currentPageIndexWithoutClones) let pagesCount = 0 - $: originalPagesCount = Math.max(pagesCount - (infinite ? CLONES_COUNT : 0), 1) // without clones - - function getOriginalCurrentPageIndex(currentPageIndex, pagesCount, infinite) { - if (infinite) { - if (currentPageIndex === pagesCount - 1) return 0 - if (currentPageIndex === 0) return (pagesCount - CLONES_COUNT) - 1 - return currentPageIndex - 1 - } - return currentPageIndex - } + $: pagesCountWithoutClones = getPagesCountWithoutClones({ + pagesCount, + oneSideClonesCount, + }) + let pagesWindowWidth = 0 let pageWidth = 0 let offset = 0 let pageWindowElement - let pagesElement + let pagesContainer let focused = false let progressValue @@ -156,27 +167,44 @@ } // used for lazy loading images, preloaded only current, adjacent and cloanable images - $: loaded = getAdjacentIndexes(originalCurrentPageIndex, originalPagesCount, infinite) + $: loaded = getAdjacentIndexes({ + pageIndex: currentPageIndexWithoutClones, + pagesCount: pagesCountWithoutClones, + infinite, + }) - function applyPageSizes() { - const children = pagesElement.children - pageWidth = pageWindowElement.clientWidth + function initPageSizes() { + const sizes = getPageSizes({ + pageWindowElement, + pagesContainerChildren: pagesContainer.children, + }) + applyPageSizes({ + pagesContainerChildren: pagesContainer.children, + pageWidth: sizes.pageWidth, + }) - pagesCount = children.length - - for (let pageIndex=0; pageIndex progressManager.reset()) - if (pagesElement && pageWindowElement) { - // load first and last child to clone them - loaded = [0, pagesElement.children.length - 1] + if (pagesContainer && pageWindowElement) { + // load first and last child to clone them + // TODO: update + loaded = [0, pagesContainer.children.length - 1] await tick() infinite && addClones() - store.init(initialPageIndex + Number(infinite)) - applyPageSizes() + store.init(initialPageIndex + oneSideClonesCount) + initPageSizes() } - addResizeEventListener(applyPageSizes) + addResizeEventListener(initPageSizes) })() }) onDestroy(() => { - removeResizeEventListener(applyPageSizes) + removeResizeEventListener(initPageSizes) cleanupFns.filter(fn => fn && typeof fn === 'function').forEach(fn => fn()) }) async function handlePageChange(pageIndex) { - await showPage(pageIndex + Number(infinite)) + await showPage(pageIndex + oneSideClonesCount) } function offsetPage(options) { @@ -245,10 +274,10 @@ let jumped = false if (infinite) { if (currentPageIndex === 0) { - await showPage(pagesCount - CLONES_COUNT, { animated: false }) + await showPage(pagesCount - 2 * oneSideClonesCount, { animated: false }) jumped = true - } else if (currentPageIndex === pagesCount - 1) { - await showPage(1, { animated: false }) + } else if (currentPageIndex === pagesCount - oneSideClonesCount ) { + await showPage(oneSideClonesCount, { animated: false }) jumped = true } } @@ -272,20 +301,29 @@ async function showPage(pageIndex, options) { await changePage( - () => store.moveToPage({ pageIndex, pagesCount }), + () => store.moveToPage({ + pageIndex, + pagesCount, + }), options ) } async function showPrevPage(options) { await changePage( - () => store.prev({ infinite, pagesCount }), - options + () => store.prev({ + infinite, + pagesCount, + }), + options, ) } async function showNextPage(options) { await changePage( - () => store.next({ infinite, pagesCount }), - options + () => store.next({ + infinite, + pagesCount, + }), + options, ) } @@ -326,7 +364,7 @@ @@ -344,7 +382,7 @@ > @@ -370,7 +408,7 @@ @@ -380,13 +418,13 @@ {#if dots} handlePageChange(event.detail)} > diff --git a/src/store.js b/src/store.js index 6eaa429..a4a2e0c 100644 --- a/src/store.js +++ b/src/store.js @@ -1,8 +1,10 @@ -import { writable } from 'svelte/store'; +import { + writable, +} from 'svelte/store'; import { getNextPageIndexFn, getPrevPageIndexFn, - getPageIndex + getPageIndex, } from './utils/page' const initState = { @@ -15,29 +17,34 @@ function createStore() { function init(initialPageIndex) { set({ ...initState, - currentPageIndex: initialPageIndex + currentPageIndex: initialPageIndex, }) } - function setCurrentPageIndex(index) { - update(store => ({ - ...store, - currentPageIndex: index, - })) - } - - function moveToPage({ pageIndex, pagesCount }) { + function moveToPage({ + pageIndex, + pagesCount, + }) { update(store => { return { ...store, - currentPageIndex: getPageIndex(pageIndex, pagesCount), + currentPageIndex: getPageIndex({ + pageIndex, + pagesCount, + }), } }) } - function next({ infinite, pagesCount }) { + function next({ + infinite, + pagesCount, + }) { update(store => { - const newCurrentPageIndex = getNextPageIndexFn(infinite)(store.currentPageIndex, pagesCount) + const newCurrentPageIndex = getNextPageIndexFn(infinite)({ + currentPageIndex: store.currentPageIndex, + pagesCount, + }) return { ...store, currentPageIndex: newCurrentPageIndex, @@ -45,9 +52,15 @@ function createStore() { }) } - function prev({ infinite, pagesCount }) { + function prev({ + infinite, + pagesCount, + }) { update(store => { - const newCurrentPageIndex = getPrevPageIndexFn(infinite)(store.currentPageIndex, pagesCount) + const newCurrentPageIndex = getPrevPageIndexFn(infinite)({ + currentPageIndex: store.currentPageIndex, + pagesCount, + }) return { ...store, currentPageIndex: newCurrentPageIndex, @@ -59,7 +72,6 @@ function createStore() { subscribe, next, prev, - setCurrentPageIndex, init, moveToPage, }; diff --git a/src/utils/page.js b/src/utils/page.js index 389faa4..59ff5bf 100644 --- a/src/utils/page.js +++ b/src/utils/page.js @@ -1,9 +1,15 @@ -export function getNextPageIndexLimited(currentPageIndex, pagesCount) { +export function getNextPageIndexLimited({ + currentPageIndex, + pagesCount, +}) { if (pagesCount < 1) throw new Error('pagesCount must be at least 1') return Math.min(Math.max(currentPageIndex + 1, 0), pagesCount - 1) } -export function getNextPageIndexInfinte(currentPageIndex, pagesCount) { +export function getNextPageIndexInfinte({ + currentPageIndex, + pagesCount, +}) { if (pagesCount < 1) throw new Error('pagesCount must be at least 1') const newCurrentPageIndex = Math.max(currentPageIndex, 0) + 1 return newCurrentPageIndex > pagesCount - 1 ? 0 : Math.max(newCurrentPageIndex, 0) @@ -13,12 +19,18 @@ export function getNextPageIndexFn(infinite) { return infinite ? getNextPageIndexInfinte : getNextPageIndexLimited } -export function getPrevPageIndexLimited(currentPageIndex, pagesCount) { +export function getPrevPageIndexLimited({ + currentPageIndex, + pagesCount, +}) { if (pagesCount < 1) throw new Error('pagesCount must be at least 1') return Math.max(Math.min(currentPageIndex - 1, pagesCount - 1), 0) } -export function getPrevPageIndexInfinte(currentPageIndex, pagesCount) { +export function getPrevPageIndexInfinte({ + currentPageIndex, + pagesCount, +}) { if (pagesCount < 1) throw new Error('pagesCount must be at least 1') const newCurrentPageIndex = Math.min(currentPageIndex, pagesCount - 1) - 1 return newCurrentPageIndex >= 0 ? Math.min(newCurrentPageIndex, pagesCount - 1) : pagesCount - 1 @@ -28,12 +40,19 @@ export function getPrevPageIndexFn(infinite) { return infinite ? getPrevPageIndexInfinte : getPrevPageIndexLimited } -export function getPageIndex(pageIndex, pagesCount) { +export function getPageIndex({ + pageIndex, + pagesCount, +}) { if (pagesCount < 1) throw new Error('pagesCount must be at least 1') return pageIndex < 0 ? 0 : Math.min(pageIndex, pagesCount - 1) } -export function getAdjacentIndexes(pageIndex, pagesCount, infinite) { +export function getAdjacentIndexes({ + pageIndex, + pagesCount, + infinite, +}) { if (pagesCount < 1) throw new Error('pagesCount must be at least 1') const _pageIndex = Math.max(0, Math.min(pageIndex, pagesCount - 1)) let rangeStart = _pageIndex - 1; @@ -50,3 +69,91 @@ export function getAdjacentIndexes(pageIndex, pagesCount, infinite) { : rangeEnd return [...new Set([rangeStart, rangeEnd, _pageIndex])].sort((a, b) => a - b) } + +export function getClones({ + oneSideClonesCount, + pagesContainerChildren, +}) { + // TODO: add fns to remove clones if needed + const clonesToAppend = [] + for (let i=0; ilen-1-oneSideClonesCount; i--) { + clonesToPrepend.push(pagesContainerChildren[i].cloneNode(true)) + } + + return { + clonesToAppend, + clonesToPrepend, + } +} + +export function applyClones({ + pagesContainer, + clonesToAppend, + clonesToPrepend, +}) { + for (let i=0; i { { currentPageIndex: 2, pagesCount: 3, expected: 2 }, { currentPageIndex: 7, pagesCount: 3, expected: 2 }, ] - testCases.forEach(({ currentPageIndex, pagesCount, expected }) => { - expect(getNextPageIndexLimited(currentPageIndex, pagesCount)).toBe(expected) + testCases.forEach(({ + currentPageIndex, + pagesCount, + expected, + }) => { + expect(getNextPageIndexLimited({ + currentPageIndex, + pagesCount, + })).toBe(expected) }) }) it('throws error if pagesCount is less than 1', () => { const currentPageIndex = 5 const pagesCount = 0 expect( - () => getNextPageIndexLimited(currentPageIndex, pagesCount) + () => getNextPageIndexLimited({ + currentPageIndex, + pagesCount, + }) ).toThrowError('pagesCount must be at least 1') }) }) @@ -38,15 +48,25 @@ describe('getNextPageIndexInfinte', () => { { currentPageIndex: 2, pagesCount: 3, expected: 0 }, { currentPageIndex: 7, pagesCount: 3, expected: 0 }, ] - testCases.forEach(({ currentPageIndex, pagesCount, expected }) => { - expect(getNextPageIndexInfinte(currentPageIndex, pagesCount)).toBe(expected) + testCases.forEach(({ + currentPageIndex, + pagesCount, + expected, + }) => { + expect(getNextPageIndexInfinte({ + currentPageIndex, + pagesCount, + })).toBe(expected) }) }) it('throws error if pagesCount is less than 1', () => { const currentPageIndex = 5 const pagesCount = 0 expect( - () => getNextPageIndexInfinte(currentPageIndex, pagesCount) + () => getNextPageIndexInfinte({ + currentPageIndex, + pagesCount, + }) ).toThrowError('pagesCount must be at least 1') }) }) @@ -60,15 +80,25 @@ describe('getPrevPageIndexLimited', () => { { currentPageIndex: 2, pagesCount: 3, expected: 1 }, { currentPageIndex: 7, pagesCount: 3, expected: 2 }, ] - testCases.forEach(({ currentPageIndex, pagesCount, expected }) => { - expect(getPrevPageIndexLimited(currentPageIndex, pagesCount)).toBe(expected) + testCases.forEach(({ + currentPageIndex, + pagesCount, + expected, + }) => { + expect(getPrevPageIndexLimited({ + currentPageIndex, + pagesCount, + })).toBe(expected) }) }) it('throws error if pagesCount is less than 1', () => { const currentPageIndex = 5 const pagesCount = 0 expect( - () => getPrevPageIndexLimited(currentPageIndex, pagesCount) + () => getPrevPageIndexLimited({ + currentPageIndex, + pagesCount, + }) ).toThrowError('pagesCount must be at least 1') }) }) @@ -82,15 +112,25 @@ describe('getPrevPageIndexInfinte', () => { { currentPageIndex: 2, pagesCount: 3, expected: 1 }, { currentPageIndex: 7, pagesCount: 3, expected: 1 }, ] - testCases.forEach(({ currentPageIndex, pagesCount, expected }) => { - expect(getPrevPageIndexInfinte(currentPageIndex, pagesCount)).toBe(expected) + testCases.forEach(({ + currentPageIndex, + pagesCount, + expected, + }) => { + expect(getPrevPageIndexInfinte({ + currentPageIndex, + pagesCount, + })).toBe(expected) }) }) it('throws error if pagesCount is less than 1', () => { const currentPageIndex = 5 const pagesCount = 0 expect( - () => getPrevPageIndexInfinte(currentPageIndex, pagesCount) + () => getPrevPageIndexInfinte({ + currentPageIndex, + pagesCount, + }) ).toThrowError('pagesCount must be at least 1') }) }) @@ -104,15 +144,25 @@ describe('getPageIndex', () => { { pageIndex: 2, pagesCount: 3, expected: 2 }, { pageIndex: 7, pagesCount: 3, expected: 2 }, ] - testCases.forEach(({ pageIndex, pagesCount, expected }) => { - expect(getPageIndex(pageIndex, pagesCount)).toBe(expected) + testCases.forEach(({ + pageIndex, + pagesCount, + expected, + }) => { + expect(getPageIndex({ + pageIndex, + pagesCount, + })).toBe(expected) }) }) it('throws error if pagesCount is less than 1', () => { const pageIndex = 5 const pagesCount = 0 expect( - () => getPageIndex(pageIndex, pagesCount) + () => getPageIndex({ + pageIndex, + pagesCount, + }) ).toThrowError('pagesCount must be at least 1') }) }) @@ -127,8 +177,16 @@ describe('getAdjacentIndexes', () => { { pageIndex: 9, pagesCount: 10, expected: [0, 8, 9] }, { pageIndex: 15, pagesCount: 10, expected: [0, 8, 9] }, ] - testCases.forEach(({ pageIndex, pagesCount, expected }) => { - expect(getAdjacentIndexes(pageIndex, pagesCount, true)).toEqual(expected) + testCases.forEach(({ + pageIndex, + pagesCount, + expected, + }) => { + expect(getAdjacentIndexes({ + pageIndex, + pagesCount, + infinite: true, + })).toEqual(expected) }) }) it('returns indexes as expected if not infinite', () => { @@ -140,8 +198,16 @@ describe('getAdjacentIndexes', () => { { pageIndex: 9, pagesCount: 10, expected: [8, 9] }, { pageIndex: 15, pagesCount: 10, expected: [8, 9] }, ] - testCases.forEach(({ pageIndex, pagesCount, expected }) => { - expect(getAdjacentIndexes(pageIndex, pagesCount, false)).toEqual(expected) + testCases.forEach(({ + pageIndex, + pagesCount, + expected, + }) => { + expect(getAdjacentIndexes({ + pageIndex, + pagesCount, + infinite: false, + })).toEqual(expected) }) }) it('throws error if pagesCount is less than 1', () => { @@ -149,7 +215,11 @@ describe('getAdjacentIndexes', () => { const pagesCount = 0 const infinite = true expect( - () => getAdjacentIndexes(pageIndex, pagesCount, infinite) + () => getAdjacentIndexes({ + pageIndex, + pagesCount, + infinite, + }) ).toThrowError('pagesCount must be at least 1') }) })