Skip to content

Commit

Permalink
feat: Type pagination (#15399)
Browse files Browse the repository at this point in the history
* feat: add types to Pagination

* refactor: update pageSizes proptype to correctly match interface

* test: update public snapshot since proptypes changed
  • Loading branch information
Tresau committed Mar 14, 2024
1 parent 4890639 commit 9346f3e
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 18 deletions.
Expand Up @@ -5831,6 +5831,7 @@ Map {
Object {
"args": Array [
Object {
"isRequired": true,
"type": "number",
},
],
Expand All @@ -5841,12 +5842,17 @@ Map {
Object {
"args": Array [
Object {
"text": undefined,
"text": Object {
"isRequired": true,
"type": "string",
},
"value": Object {
"isRequired": true,
"type": "number",
},
},
],
"isRequired": true,
"type": "shape",
},
],
Expand Down
Expand Up @@ -11,7 +11,15 @@ import cx from 'classnames';
import SkeletonText from '../SkeletonText';
import { usePrefix } from '../../internal/usePrefix';

function PaginationSkeleton({ className, ...rest }) {
export interface PaginationSkeletonProps
extends React.HTMLAttributes<HTMLDivElement> {
/**
* Specify an optional className to add.
*/
className?: string;
}

function PaginationSkeleton({ className, ...rest }: PaginationSkeletonProps) {
const prefix = usePrefix();
return (
<div
Expand Down
Expand Up @@ -16,6 +16,124 @@ import { useFallbackId } from '../../internal/useId';
import { usePrefix } from '../../internal/usePrefix';
import { IconButton } from '../IconButton';

type ExcludedAttributes = 'id' | 'onChange';

export interface PaginationPageSize {
text: string;
value: number;
}

export interface PaginationProps
extends Omit<React.HTMLAttributes<HTMLDivElement>, ExcludedAttributes> {
/**
* The description for the backward icon.
*/
backwardText?: string;

/**
* The CSS class names.
*/
className?: string;

/**
* `true` if the backward/forward buttons, as well as the page select elements, should be disabled.
*/
disabled?: boolean;

/**
* The description for the forward icon.
*/
forwardText?: string;

/**
* The unique ID of this component instance.
*/
id?: string | number;

// TODO: remove when v9 is deprecated
/**
* `true` if the current page should be the last page.
*/
isLastPage?: boolean;

/**
* The function returning a translatable text showing where the current page is,
* in a manner of the range of items.
*/
itemRangeText?: (min: number, max: number, total: number) => string;

/**
* A variant of `itemRangeText`, used if the total number of items is unknown.
*/
itemText?: (min: number, max: number) => string;

/**
* The translatable text indicating the number of items per page.
*/
itemsPerPageText?: string;

/**
* The callback function called when the current page changes.
*/
onChange?: (data: {
page: number;
pageSize: number;
ref?: React.RefObject<any>;
}) => void;

/**
* The current page.
*/
page?: number;

/**
* `true` if the select box to change the page should be disabled.
*/
pageInputDisabled?: boolean;

pageNumberText?: string;

/**
* A function returning PII showing where the current page is.
*/
pageRangeText?: (current: number, total: number) => string;

/**
* The number dictating how many items a page contains.
*/
pageSize?: number;

/**
* `true` if the select box to change the items per page should be disabled.
*/
pageSizeInputDisabled?: boolean;

/**
* The choices for `pageSize`.
*/
pageSizes: number[] | PaginationPageSize[];

/**
* The translatable text showing the current page.
*/
pageText?: (page: number, pagesUnknown?: boolean) => string;

/**
* `true` if the total number of items is unknown.
*/
pagesUnknown?: boolean;

/**
* Specify the size of the Pagination.
*/
size?: 'sm' | 'md' | 'lg';

/**
* The total number of items.
*/
totalItems?: number;
}

function mapPageSizesToObject(sizes) {
return typeof sizes[0] === 'object' && sizes[0] !== null
? sizes
Expand All @@ -24,7 +142,7 @@ function mapPageSizesToObject(sizes) {

function renderSelectItems(total) {
let counter = 1;
let itemArr = [];
const itemArr: React.ReactNode[] = [];
while (counter <= total) {
itemArr.push(
<SelectItem key={counter} value={counter} text={String(counter)} />
Expand All @@ -50,7 +168,7 @@ function getPageSize(pageSizes, pageSize) {
const Pagination = React.forwardRef(function Pagination(
{
backwardText = 'Previous page',
className: customClassName,
className: customClassName = '',
disabled = false,
forwardText = 'Next page',
id,
Expand All @@ -70,15 +188,15 @@ const Pagination = React.forwardRef(function Pagination(
pageText = (page, pagesUnknown) => `page ${pagesUnknown ? '' : page}`,
pagesUnknown = false,
size = 'md',
totalItems,
totalItems = 1,
...rest
},
ref
}: PaginationProps,
ref: React.Ref<HTMLDivElement>
) {
const prefix = usePrefix();
const inputId = useFallbackId(id);
const backBtnRef = useRef(null);
const forwardBtnRef = useRef(null);
const inputId = useFallbackId(id?.toString());
const backBtnRef = useRef<HTMLButtonElement>(null);
const forwardBtnRef = useRef<HTMLButtonElement>(null);
const [pageSizes, setPageSizes] = useState(() => {
return mapPageSizesToObject(controlledPageSizes);
});
Expand Down Expand Up @@ -178,15 +296,15 @@ const Pagination = React.forwardRef(function Pagination(
// the icon button becomes disabled and the focus shifts to `main`
// this presents an a11y problem for keyboard & screen reader users
// instead, we want the focus to shift to the other pagination btn
if (nextPage === totalPages) {
if (nextPage === totalPages && backBtnRef?.current) {
backBtnRef.current.focus();
}

if (onChange) {
onChange({
page: nextPage,
pageSize,
backBtnRef,
ref: backBtnRef,
});
}
}
Expand All @@ -199,15 +317,15 @@ const Pagination = React.forwardRef(function Pagination(
// the icon button becomes disabled and the focus shifts to `main`
// this presents an a11y problem for keyboard & screen reader users
// instead, we want the focus to shift to the other pagination btn
if (nextPage === 1) {
if (nextPage === 1 && forwardBtnRef?.current) {
forwardBtnRef.current.focus();
}

if (onChange) {
onChange({
page: nextPage,
pageSize,
forwardBtnRef,
ref: forwardBtnRef,
});
}
}
Expand Down Expand Up @@ -388,12 +506,12 @@ Pagination.propTypes = {
* The choices for `pageSize`.
*/
pageSizes: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.number),
PropTypes.arrayOf(PropTypes.number.isRequired),
PropTypes.arrayOf(
PropTypes.shape({
text: PropTypes.text,
value: PropTypes.number,
})
text: PropTypes.string.isRequired,
value: PropTypes.number.isRequired,
}).isRequired
),
]).isRequired,

Expand Down

0 comments on commit 9346f3e

Please sign in to comment.