diff --git a/packages/lib/src/spatial-navigation/components/virtualizedList/helpers/computeTranslation.test.ts b/packages/lib/src/spatial-navigation/components/virtualizedList/helpers/computeTranslation.test.ts index 73320629..dbacf154 100644 --- a/packages/lib/src/spatial-navigation/components/virtualizedList/helpers/computeTranslation.test.ts +++ b/packages/lib/src/spatial-navigation/components/virtualizedList/helpers/computeTranslation.test.ts @@ -290,6 +290,138 @@ describe('computeTranslation for virtualized list with stick-to-end scroll behav }); }); +describe('computeTranslation for virtualized list with stick-to-center scroll behavior', () => { + const scrollBehavior = 'stick-to-center'; + + it('should not scroll if currentlyFocusedItemIndex < numberOfItemsVisibleOnScreen', () => { + const expectedResult = computeTranslation({ + itemSizeInPx, + currentlyFocusedItemIndex: 3, + numberOfItemsVisibleOnScreen: 4, + nbMaxOfItems: 11, + scrollBehavior: scrollBehavior, + data, + listSizeInPx: 40, + maxPossibleLeftAlignedIndex: 7, + maxPossibleRightAlignedIndex: 3, + }); + + expect(expectedResult).toEqual(-0); + }); + + it('should not scroll if currentlyFocusedItemIndex < numberOfItemsVisibleOnScreen with dynamic sizes', () => { + const expectedResult = computeTranslation({ + itemSizeInPx: itemSizeInPxFunction, + currentlyFocusedItemIndex: 3, + numberOfItemsVisibleOnScreen: 4, + nbMaxOfItems: 11, + scrollBehavior: scrollBehavior, + data, + listSizeInPx: 40, + maxPossibleLeftAlignedIndex: 7, + maxPossibleRightAlignedIndex: 3, + }); + + expect(expectedResult).toEqual(-0); + }); + + it('should end-align focused item', () => { + const expectedResult = computeTranslation({ + itemSizeInPx, + currentlyFocusedItemIndex: 6, + numberOfItemsVisibleOnScreen: 4, + nbMaxOfItems: 11, + scrollBehavior: scrollBehavior, + data, + listSizeInPx: 40, + maxPossibleLeftAlignedIndex: 7, + maxPossibleRightAlignedIndex: 3, + }); + + expect(expectedResult).toEqual(-30); + }); + + it('should end-align focused item with dynamic sizes', () => { + const expectedResult = computeTranslation({ + itemSizeInPx: itemSizeInPxFunction, + currentlyFocusedItemIndex: 6, + numberOfItemsVisibleOnScreen: 4, + nbMaxOfItems: 11, + scrollBehavior: scrollBehavior, + data, + listSizeInPx: 40, + maxPossibleLeftAlignedIndex: 7, + maxPossibleRightAlignedIndex: 3, + }); + + expect(expectedResult).toEqual(-60); + }); + + it('should end-align last element if focused', () => { + const expectedResult = computeTranslation({ + itemSizeInPx, + currentlyFocusedItemIndex: 10, + numberOfItemsVisibleOnScreen: 4, + nbMaxOfItems: 11, + scrollBehavior: scrollBehavior, + data, + listSizeInPx: 40, + maxPossibleLeftAlignedIndex: 7, + maxPossibleRightAlignedIndex: 3, + }); + + expect(expectedResult).toEqual(-70); + }); + + it('should end-align last element if focused with dynamic sizes', () => { + const expectedResult = computeTranslation({ + itemSizeInPx: itemSizeInPxFunction, + currentlyFocusedItemIndex: 10, + numberOfItemsVisibleOnScreen: 4, + nbMaxOfItems: 11, + scrollBehavior: scrollBehavior, + data, + listSizeInPx: 40, + maxPossibleLeftAlignedIndex: 7, + maxPossibleRightAlignedIndex: 3, + }); + + expect(expectedResult).toEqual(-120); + }); + + it('should start-align first element if numberOfItems <= numberOfVisibleItemsOnScreen', () => { + const expectedResult = computeTranslation({ + itemSizeInPx, + currentlyFocusedItemIndex: 1, + numberOfItemsVisibleOnScreen: 4, + nbMaxOfItems: 3, + scrollBehavior: scrollBehavior, + data, + listSizeInPx: 40, + maxPossibleLeftAlignedIndex: 7, + maxPossibleRightAlignedIndex: 3, + }); + + expect(expectedResult).toEqual(-0); + }); + + it('should start-align first element if numberOfItems <= numberOfVisibleItemsOnScreen with dynamic sizes', () => { + const expectedResult = computeTranslation({ + itemSizeInPx: itemSizeInPxFunction, + currentlyFocusedItemIndex: 1, + numberOfItemsVisibleOnScreen: 4, + nbMaxOfItems: 3, + scrollBehavior: scrollBehavior, + data: data.slice(0, 2), + listSizeInPx: 40, + maxPossibleLeftAlignedIndex: 0, + maxPossibleRightAlignedIndex: 2, + }); + + expect(expectedResult).toEqual(-0); + }); +}); + describe('computeTranslation for virtualized list with jumping scroll behavior', () => { const scrollBehavior = 'jump-on-scroll'; diff --git a/packages/lib/src/spatial-navigation/components/virtualizedList/helpers/computeTranslation.ts b/packages/lib/src/spatial-navigation/components/virtualizedList/helpers/computeTranslation.ts index 73d37559..3b677b6f 100644 --- a/packages/lib/src/spatial-navigation/components/virtualizedList/helpers/computeTranslation.ts +++ b/packages/lib/src/spatial-navigation/components/virtualizedList/helpers/computeTranslation.ts @@ -24,11 +24,15 @@ const computeStickToCenterTranslation = ({ itemSizeInPx, data, listSizeInPx, + maxPossibleRightAlignedIndex, + maxPossibleLeftAlignedIndex, }: { currentlyFocusedItemIndex: number; itemSizeInPx: number | ((item: T) => number); data: T[]; listSizeInPx: number; + maxPossibleRightAlignedIndex: number; + maxPossibleLeftAlignedIndex: number; }) => { const currentlyFocusedItemSize = typeof itemSizeInPx === 'function' @@ -51,13 +55,35 @@ const computeStickToCenterTranslation = ({ if (sizeOfListFromStartToCurrentlyFocusedItem < listSizeInPx / 2) { return 0; } - - if (sizeOfListFromEndToCurrentlyFocusedItem < listSizeInPx / 2) { - return -sizeOfListFromStartToCurrentlyFocusedItem + listSizeInPx - sizeOfListFromEndToCurrentlyFocusedItem - currentlyFocusedItemSize; + + if (currentlyFocusedItemIndex > maxPossibleLeftAlignedIndex) { + console.log('currentlyFocusedItemIndex', currentlyFocusedItemIndex); } + // if (sizeOfListFromEndToCurrentlyFocusedItem < listSizeInPx / 2) { + // console.log('-----------'); + // console.log('currentlyFocusedItemIndex', currentlyFocusedItemIndex); + // const result = + // sizeOfListFromStartToCurrentlyFocusedItem - + // listSizeInPx + + // sizeOfListFromEndToCurrentlyFocusedItem + + // currentlyFocusedItemSize; + // console.log('list END inferior to half list size in px', result); + // console.log( + // 'sizeOfListFromStartToCurrentlyFocusedItem', + // sizeOfListFromStartToCurrentlyFocusedItem, + // ); + // console.log('listSizeInPx', listSizeInPx); + // console.log('sizeOfListFromEndToCurrentlyFocusedItem', sizeOfListFromEndToCurrentlyFocusedItem); + // console.log('currentlyFocusedItemSize', currentlyFocusedItemSize); + // console.log('-----------'); + + // return -result; + // } + const scrollOffset = - sizeOfListFromStartToCurrentlyFocusedItem - (listSizeInPx / 2) + (currentlyFocusedItemSize / 2); + sizeOfListFromStartToCurrentlyFocusedItem - listSizeInPx / 2 + currentlyFocusedItemSize / 2; + return -scrollOffset; }; @@ -150,6 +176,8 @@ export const computeTranslation = ({ itemSizeInPx, data, listSizeInPx, + maxPossibleLeftAlignedIndex, + maxPossibleRightAlignedIndex, }); case 'stick-to-end': return computeStickToEndTranslation({ diff --git a/packages/lib/src/spatial-navigation/components/virtualizedList/helpers/createScrollOffsetArray.test.ts b/packages/lib/src/spatial-navigation/components/virtualizedList/helpers/createScrollOffsetArray.test.ts new file mode 100644 index 00000000..ef7f5a73 --- /dev/null +++ b/packages/lib/src/spatial-navigation/components/virtualizedList/helpers/createScrollOffsetArray.test.ts @@ -0,0 +1,40 @@ +// Import the function to test + +import { computeAllScrollOffsets } from './createScrollOffsetArray'; + +// Mock data and inputs +const itemSize = (item) => item.size; +// doesn't matter here +const numberOfItemsVisibleOnScreen = 0; +const data = [ + { name: 'data 0', size: 1 }, + { name: 'data 1', size: 1 }, + { name: 'data 2', size: 2 }, + { name: 'data 3', size: 1 }, + { name: 'data 4', size: 1 }, + { name: 'data 5', size: 2 }, + { name: 'data 6', size: 1 }, + { name: 'data 7', size: 1 }, + { name: 'data 8', size: 2 }, + { name: 'data 9', size: 1 }, + { name: 'data 10', size: 1 }, +]; +const nbMaxOfItems = data.length; +const scrollBehavior = 'stick-to-center'; +const listSizeInPx = 5; + +// Expected output +const expectedOutput = [0, 0, -0.5, -2, -3, -4.5, -6, -7, -8.5, -9, -9]; + +test('computeAllScrollOffsets returns an array of zeros with the same length as data', () => { + const result = computeAllScrollOffsets({ + itemSize, + nbMaxOfItems, + numberOfItemsVisibleOnScreen, + scrollBehavior, + data, + listSizeInPx, + }); + + expect(result).toEqual(expectedOutput); +});