@equinor/eds-core-react
Version:
The React implementation of the Equinor Design System
152 lines (147 loc) • 5.69 kB
JavaScript
import { forwardRef, useState } from 'react';
import styled from 'styled-components';
import { useIsMounted, useIsomorphicLayoutEffect } from '@equinor/eds-utils';
import { Button } from '../Button/index.js';
import { Icon } from '../Icon/index.js';
import { PaginationItem } from './PaginationItem.js';
import { pagination } from './Pagination.tokens.js';
import { chevron_left, chevron_right, more_horizontal } from '@equinor/eds-icons';
import { PaginationControl } from './paginationControl.js';
import { jsx, jsxs } from 'react/jsx-runtime';
import { Typography } from '../Typography/Typography.js';
const icons = {
chevron_left,
chevron_right,
more_horizontal
};
Icon.add(icons);
const Navigation = styled.nav.withConfig({
displayName: "Pagination__Navigation",
componentId: "sc-13cpp3o-0"
})(["display:flex;justify-content:space-between;align-items:center;flex-wrap:nowrap;margin-left:", ";"], ({
$withItemIndicator
}) => $withItemIndicator ? pagination.spacings.left : 0);
const OrderedList = styled.ol.withConfig({
displayName: "Pagination__OrderedList",
componentId: "sc-13cpp3o-1"
})(["list-style:none;margin:0;padding:0;display:grid;grid-gap:", ";grid-auto-flow:column;"], pagination.spacings.left);
const ListItem = styled.li.withConfig({
displayName: "Pagination__ListItem",
componentId: "sc-13cpp3o-2"
})(["display:inline-grid;"]);
const StyledIcon = styled(Icon).withConfig({
displayName: "Pagination__StyledIcon",
componentId: "sc-13cpp3o-3"
})(["align-self:center;justify-self:center;fill:", ";"], pagination.entities.icon.typography.color);
const FlexContainer = styled.div.withConfig({
displayName: "Pagination__FlexContainer",
componentId: "sc-13cpp3o-4"
})(["display:flex;justify-content:space-between;flex-wrap:nowrap;align-items:center;"]);
const Text = styled(Typography).withConfig({
displayName: "Pagination__Text",
componentId: "sc-13cpp3o-5"
})(["white-space:nowrap;"]);
function getAriaLabel(page, selected) {
return `${selected === page ? 'Current page, ' : 'Go to '}page ${page}`;
}
const Pagination = /*#__PURE__*/forwardRef(function Pagination({
totalItems,
defaultPage = 1,
withItemIndicator,
itemsPerPage = 10,
onChange,
...rest
}, ref) {
const pages = Math.ceil(totalItems / itemsPerPage); // Total page numbers
const columns = pages < 5 ? pages + 2 : 7; // Total pages to display on the control + 2: < and >
const [activePage, setActivePage] = useState(defaultPage);
const currentItemFirst = activePage === 1 ? 1 : activePage * itemsPerPage - itemsPerPage + 1; // First number of range of items at current page
const currentItemLast = activePage === pages ? totalItems : activePage * itemsPerPage; // Last number of range of items at current page
const onPageChange = (event, page) => {
page && setActivePage(page);
if (event && onChange) {
// Callback for provided onChange func
onChange(event, page);
} else {
return undefined;
}
};
const isMounted = useIsMounted();
const items = PaginationControl(pages, activePage);
useIsomorphicLayoutEffect(() => {
if (isMounted) {
setActivePage(1);
onChange?.(null, 1);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [itemsPerPage]);
const props = {
ref,
$withItemIndicator: withItemIndicator,
...rest
};
const pagination = /*#__PURE__*/jsx(Navigation, {
"aria-label": "pagination",
...props,
children: /*#__PURE__*/jsxs(OrderedList, {
style: {
gridTemplateColumns: `repeat(${columns}, 48px)`
},
children: [/*#__PURE__*/jsx(ListItem, {
children: /*#__PURE__*/jsx(Button, {
variant: "ghost_icon",
onClick: activePage > 1 ? event => {
onPageChange(event, activePage - 1);
} : undefined,
disabled: activePage === 1,
"aria-label": "Go to previous page",
children: /*#__PURE__*/jsx(Icon, {
name: "chevron_left"
})
})
}, "previous"), items.length > 0 ? items.map((page, index) => page !== 'ELLIPSIS' ? /*#__PURE__*/jsx(ListItem
// eslint-disable-next-line react/no-array-index-key
, {
children: /*#__PURE__*/jsx(PaginationItem, {
"aria-label": getAriaLabel(page, activePage),
"aria-current": activePage,
$page: page,
selected: page === activePage,
onClick: event => {
onPageChange(event, page);
}
})
}, `list-item ${index}`) : /*#__PURE__*/jsx(ListItem
// eslint-disable-next-line react/no-array-index-key
, {
children: /*#__PURE__*/jsx(StyledIcon, {
name: "more_horizontal",
"aria-label": "Ellipsis of pages"
})
}, `ellipsis-${index}`)) : undefined, /*#__PURE__*/jsx(ListItem, {
children: /*#__PURE__*/jsx(Button, {
variant: "ghost_icon",
onClick: activePage < pages ? event => {
onPageChange(event, activePage + 1);
} : undefined,
"aria-label": "Go to next page",
disabled: activePage === pages,
children: /*#__PURE__*/jsx(Icon, {
name: "chevron_right"
})
})
}, "next")]
})
});
return withItemIndicator ? /*#__PURE__*/jsxs(FlexContainer, {
children: [/*#__PURE__*/jsx(Text, {
children: currentItemFirst !== currentItemLast ? `${currentItemFirst}
${' - '}
${currentItemLast}
${' of '}
${totalItems}
${' items'}` : `${currentItemFirst} ${' of '} ${totalItems} ${' items'}`
}), pagination]
}) : pagination;
});
export { Pagination };