Skip to content

Commit

Permalink
Add new pager display mode
Browse files Browse the repository at this point in the history
This adds a new pager display mode to customize what table data the pager shows
  • Loading branch information
ghsteff committed Dec 11, 2023
1 parent 9f0f461 commit 329c483
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 57 deletions.
5 changes: 4 additions & 1 deletion docs/components/data/Pager.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import * as PagerStories from '../../../src/data/Pager/Pager.story'

# Pager
A simple pager for navigating between pages of data. You can customise the page navigation indicators (The pager arrows) if you want.
You can also change the `displayMode` to customize what table information the pager shows.

## Example
<Canvas sourceState="shown" of={PagerStories.Basic} />
<Canvas sourceState="shown" of={PagerStories.ShowPages} />
<Canvas sourceState="shown" of={PagerStories.ShowItems} />
<Canvas sourceState="shown" of={PagerStories.ShowAll} />

## API
<ArgsTable of={Pager} />
4 changes: 4 additions & 0 deletions src/data/Pager/Pager.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,8 @@
color: var(--input-color);
}
}

.items {
margin-right: var(--spacing-sm);
}
}
40 changes: 38 additions & 2 deletions src/data/Pager/Pager.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,44 @@ export default {
component: Pager
};

export const Basic = () => {
export const ShowPages = () => {
const [page, setPage] = useState<number>(0);

return <Pager page={page} size={10} total={100} onPageChange={setPage} />;
return (
<Pager
page={page}
size={10}
total={100}
onPageChange={setPage}
displayMode="pages"
/>
);
};

export const ShowItems = () => {
const [page, setPage] = useState<number>(0);

return (
<Pager
page={page}
size={10}
total={100}
onPageChange={setPage}
displayMode="items"
/>
);
};

export const ShowAll = () => {
const [page, setPage] = useState<number>(0);

return (
<Pager
page={page}
size={10}
total={100}
onPageChange={setPage}
displayMode="all"
/>
);
};
136 changes: 86 additions & 50 deletions src/data/Pager/Pager.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import React, { FC, Fragment, ReactNode, useCallback } from 'react';
import classNames from 'classnames';
import { Button } from '../../elements/Button';
import { FUZZY_RANGE, getPageRange } from './utils';

import { ReactComponent as PreviousArrow } from './assets/arrow-previous.svg';
import { Button } from '../../elements/Button';
import { Stack } from '../../layout';
import { Text } from '../../typography';
import { Pluralize } from '../Pluralize';
import { ReactComponent as EndArrow } from './assets/arrow-end.svg';
import { ReactComponent as NextArrow } from './assets/arrow-next.svg';
import { ReactComponent as PreviousArrow } from './assets/arrow-previous.svg';
import { ReactComponent as StartArrow } from './assets/arrow-start.svg';
import { ReactComponent as EndArrow } from './assets/arrow-end.svg';

import { FUZZY_RANGE, getItemsRange, getPageRange } from './utils';
import css from './Pager.module.css';

export interface PagerProps {
Expand Down Expand Up @@ -60,6 +62,11 @@ export interface PagerProps {
* A callback function that is called when the page changes.
*/
onPageChange?: (page: number) => void;

/**
* The type of table data for the pager to display.
*/
displayMode?: 'pages' | 'items' | 'all';
}

export const Pager: FC<PagerProps> = ({
Expand All @@ -72,12 +79,14 @@ export const Pager: FC<PagerProps> = ({
endArrow,
previousArrow,
nextArrow,
onPageChange
onPageChange,
displayMode
}) => {
const pageCount = Math.ceil(total / size);
const canPrevious = page !== 0;
const canNext = page < pageCount - 1;
const [startPage, endPage] = getPageRange(page, pageCount - 1);
const [startItem, endItem] = getItemsRange(page, size, total);

const previousPage = useCallback(() => {
if (canPrevious) {
Expand All @@ -101,16 +110,36 @@ export const Pager: FC<PagerProps> = ({

return (
<div className={classNames(css.pager, className)}>
<Button
variant="text"
size="small"
disablePadding
title="First Page"
onClick={() => onPageChange?.(0)}
disabled={!canPrevious}
>
{startArrow}
</Button>
{(displayMode === 'items' || displayMode === 'all') && (
<div className={css.items}>
{pageCount === 1 && total > 0 && (
<Text>
Showing {total === 1 ? total : `all ${total.toLocaleString()}`}{' '}
<Pluralize count={total} singular="item" showCount={false} />
</Text>
)}
{pageCount > 1 && (
<Stack dense>
<Text>
{startItem.toLocaleString()}-{endItem.toLocaleString()} of{' '}
<Pluralize count={total} singular="item" />
</Text>
</Stack>
)}
</div>
)}
{startArrow && (
<Button
variant="text"
size="small"
disablePadding
title="First Page"
onClick={() => onPageChange?.(0)}
disabled={!canPrevious}
>
{startArrow}
</Button>
)}
<Button
variant="text"
size="small"
Expand All @@ -121,31 +150,35 @@ export const Pager: FC<PagerProps> = ({
>
{previousArrow}
</Button>
{startPage >= 2 && <div className={css.overflow}>&nbsp;...</div>}
{[...Array(pageCount)].map((_, i) => (
<Fragment key={i}>
{i >= startPage && i <= endPage && (
<Button
variant="text"
size="small"
disabled={page === i}
title={`Page ${i + 1}`}
className={classNames(
css.page,
{
[css.active]: page === i
},
pageClassName
{(displayMode === 'pages' || displayMode === 'all') && (
<>
{startPage >= 2 && <div className={css.overflow}>&nbsp;...</div>}
{[...Array(pageCount)].map((_, i) => (
<Fragment key={i}>
{i >= startPage && i <= endPage && (
<Button
variant="text"
size="small"
disabled={page === i}
title={`Page ${i + 1}`}
className={classNames(
css.page,
{
[css.active]: page === i
},
pageClassName
)}
onClick={() => onPageChange?.(i)}
>
{(i + 1).toLocaleString()}
</Button>
)}
onClick={() => onPageChange?.(i)}
>
{(i + 1).toLocaleString()}
</Button>
</Fragment>
))}
{endPage <= pageCount - FUZZY_RANGE && (
<div className={css.overflow}>...&nbsp;</div>
)}
</Fragment>
))}
{endPage <= pageCount - FUZZY_RANGE && (
<div className={css.overflow}>...&nbsp;</div>
</>
)}
<Button
variant="text"
Expand All @@ -157,16 +190,18 @@ export const Pager: FC<PagerProps> = ({
>
{nextArrow}
</Button>
<Button
size="small"
title="Last Page"
disablePadding
variant="text"
onClick={() => onPageChange?.(pageCount - 1)}
disabled={!canNext}
>
{endArrow}
</Button>
{endArrow && (
<Button
size="small"
title="Last Page"
disablePadding
variant="text"
onClick={() => onPageChange?.(pageCount - 1)}
disabled={!canNext}
>
{endArrow}
</Button>
)}
</div>
);
};
Expand All @@ -175,5 +210,6 @@ Pager.defaultProps = {
previousArrow: <PreviousArrow />,
nextArrow: <NextArrow />,
startArrow: <StartArrow />,
endArrow: <EndArrow />
endArrow: <EndArrow />,
displayMode: 'pages'
};
6 changes: 5 additions & 1 deletion src/data/Pager/assets/arrow-end.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion src/data/Pager/assets/arrow-next.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion src/data/Pager/assets/arrow-previous.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion src/data/Pager/assets/arrow-start.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions src/data/Pager/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,15 @@ export function getPageRange(page: number, totalPages: number) {

return [startPage, endPage];
}

export function getItemsRange(
page: number,
perPage: number,
totalItems: number
) {
const startItem = page * perPage + 1;
const endOfPage = (page + 1) * perPage;
const endItem = Math.min(endOfPage, totalItems);

return [startItem, endItem];
}

0 comments on commit 329c483

Please sign in to comment.