diff --git a/packages/react-instantsearch-dom/src/components/Pagination.js b/packages/react-instantsearch-dom/src/components/Pagination.js index afb99dde73..e72c525d54 100644 --- a/packages/react-instantsearch-dom/src/components/Pagination.js +++ b/packages/react-instantsearch-dom/src/components/Pagination.js @@ -1,9 +1,8 @@ -import { range } from 'lodash'; import React, { Component } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import { translatable } from 'react-instantsearch-core'; -import { createClassNames, capitalize } from '../core/utils'; +import { createClassNames, capitalize, range } from '../core/utils'; import LinkList from './LinkList'; const cx = createClassNames('Pagination'); @@ -29,7 +28,7 @@ function calculatePaddingLeft(currentPage, padding, maxPages, size) { function getPages(currentPage, maxPages, padding) { const size = calculateSize(padding, maxPages); // If the widget size is equal to the max number of pages, return the entire page range - if (size === maxPages) return range(1, maxPages + 1); + if (size === maxPages) return range({ start: 1, end: maxPages + 1 }); const paddingLeft = calculatePaddingLeft( currentPage, @@ -41,7 +40,7 @@ function getPages(currentPage, maxPages, padding) { const first = currentPage - paddingLeft; const last = currentPage + paddingRight; - return range(first + 1, last + 1); + return range({ start: first + 1, end: last + 1 }); } class Pagination extends Component { diff --git a/packages/react-instantsearch-dom/src/core/__tests__/utils.js b/packages/react-instantsearch-dom/src/core/__tests__/utils.js index 8b9006e519..b2f36b0731 100644 --- a/packages/react-instantsearch-dom/src/core/__tests__/utils.js +++ b/packages/react-instantsearch-dom/src/core/__tests__/utils.js @@ -47,4 +47,35 @@ describe('utils', () => { expect(utils.capitalize('')).toBe(''); }); }); + + describe('range', () => { + test('with end', () => { + expect(utils.range({ end: 4 })).toEqual([0, 1, 2, 3]); + }); + + test('with start and end', () => { + expect(utils.range({ start: 1, end: 5 })).toEqual([1, 2, 3, 4]); + }); + + test('with end and step', () => { + expect(utils.range({ end: 20, step: 5 })).toEqual([0, 5, 10, 15]); + }); + + test('rounds decimal array lengths', () => { + // (5000 - 1) / 500 = 9.998 so we want the array length to be rounded to 10. + expect(utils.range({ start: 1, end: 5000, step: 500 })).toHaveLength(10); + expect(utils.range({ start: 1, end: 5000, step: 500 })).toEqual([ + 500, + 1000, + 1500, + 2000, + 2500, + 3000, + 3500, + 4000, + 4500, + 5000, + ]); + }); + }); }); diff --git a/packages/react-instantsearch-dom/src/core/utils.ts b/packages/react-instantsearch-dom/src/core/utils.ts index f8ce49c5fc..235d1b2fb3 100644 --- a/packages/react-instantsearch-dom/src/core/utils.ts +++ b/packages/react-instantsearch-dom/src/core/utils.ts @@ -27,3 +27,26 @@ export const isSpecialClick = (event: MouseEvent) => { export const capitalize = (key: string) => key.length === 0 ? '' : `${key[0].toUpperCase()}${key.slice(1)}`; + +type RangeOptions = { + start?: number; + end: number; + step?: number; +}; + +// taken from InstantSearch.js/utils +export function range({ start = 0, end, step = 1 }: RangeOptions): number[] { + // We can't divide by 0 so we re-assign the step to 1 if it happens. + const limitStep = step === 0 ? 1 : step; + + // In some cases the array to create has a decimal length. + // We therefore need to round the value. + // Example: + // { start: 1, end: 5000, step: 500 } + // => Array length = (5000 - 1) / 500 = 9.998 + const arrayLength = Math.round((end - start) / limitStep); + + return [...Array(arrayLength)].map( + (_, current) => (start + current) * limitStep + ); +}