UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

277 lines (276 loc) 9.74 kB
"use client"; import _includesInstanceProperty from "core-js-pure/stable/instance/includes.js"; import { Fragment, useContext, useEffect, useRef, useState } from 'react'; import { clsx } from 'clsx'; import { dispatchCustomElementEvent, extendPropsWithContext } from "../../shared/component-helper.js"; import { calculatePagination, getDotsAriaLabel } from "./PaginationCalculation.js"; import PaginationContext from "./PaginationContext.js"; import Context from "../../shared/Context.js"; import Button from "../button/Button.js"; import IconPrimary from "../icon-primary/IconPrimary.js"; import styleProperties from "../../style/themes/ui/properties.js"; import { useSpacing } from "../space/SpacingUtils.js"; import withComponentMarkers from "../../shared/helpers/withComponentMarkers.js"; import { isModifiedClickEvent } from "../../shared/helpers.js"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; const PaginationBar = localProps => { const context = useContext(PaginationContext); const sharedContext = useContext(Context); const props = extendPropsWithContext(localProps, {}, context.pagination); const { currentPageInternal, pageCountInternal, disabled, skeleton: skeletonProp, space, transformNavigationItem } = props; const skeleton = skeletonProp !== null && skeletonProp !== void 0 ? skeletonProp : sharedContext?.skeleton; const focusPage = () => { const { onPageUpdate, contentRef } = props; onPageUpdate(() => { try { const elem = contentRef.current; elem.focus(); } catch (e) {} }); }; const keepPageHeight = () => { try { const elem = props.contentRef.current; const pageHeight = elem.offsetHeight; elem.style.height = `${pageHeight / 16}rem`; elem.style.minHeight = elem.style.height; } catch (e) {} const { onPageUpdate } = props; onPageUpdate(() => { try { const elem = props.contentRef.current; elem.style.height = 'auto'; elem.style.minHeight = elem.style.height; } catch (e) {} }); }; const setPage = (currentPageInternal, event = null) => { keepPageHeight(); const { setState: setContextState, updatePageContent } = props; setContextState({ currentPageInternal }); updatePageContent(currentPageInternal); dispatchCustomElementEvent(props, 'onChange', { pageNumber: currentPageInternal, ...props, event }); }; const setPrevPage = (event = null) => { if (isModifiedClickEvent(event)) { return; } if (event?.currentTarget instanceof HTMLAnchorElement) { event.preventDefault(); } setPage(props.currentPageInternal - 1); }; const setNextPage = (event = null) => { if (isModifiedClickEvent(event)) { return; } if (event?.currentTarget instanceof HTMLAnchorElement) { event.preventDefault(); } setPage(props.currentPageInternal + 1); }; const clickHandler = ({ pageNumber, event }) => { const currentTarget = event?.currentTarget; const isAnchorLikeElement = currentTarget instanceof HTMLAnchorElement || currentTarget?.getAttribute?.('href'); if (isAnchorLikeElement && isModifiedClickEvent(event)) { return; } if (isAnchorLikeElement) { event?.preventDefault(); } setPage(pageNumber, event); focusPage(); }; const { getTranslation } = useContext(Context); const { buttonTitle, prevTitle, nextTitle, morePages } = extendPropsWithContext(props, {}, getTranslation(props).Pagination); const prevIsDisabled = currentPageInternal > -1 ? currentPageInternal === 1 : true; const nextIsDisabled = currentPageInternal > -1 ? currentPageInternal === pageCountInternal || pageCountInternal === 0 : true; const paginationBarRef = useRef(null); const currentScreenSize = useResizeObserver(paginationBarRef); const pageNumberGroups = calculatePagination(pageCountInternal, currentPageInternal, currentScreenSize === 'small'); const renderPaginationButton = (pageNumber, extraClassName) => { const isCurrent = pageNumber === currentPageInternal; const label = buttonTitle.replace('%s', String(pageNumber)); if (!transformNavigationItem) { return _jsx(Button, { className: clsx('dnb-pagination__button', extraClassName), text: String(pageNumber), "aria-label": label, variant: isCurrent ? 'primary' : 'secondary', disabled: disabled, skeleton: skeleton, "aria-current": isCurrent ? 'page' : null, onClick: event => clickHandler({ pageNumber, event }) }, pageNumber); } if (isCurrent && !skeleton) { return _jsx("span", { className: clsx('dnb-pagination__button', 'dnb-pagination__button--current', extraClassName), "aria-label": label, "aria-current": "page", children: String(pageNumber) }, pageNumber); } return _jsx(Fragment, { children: transformNavigationItem(pageNumber, { className: clsx('dnb-pagination__button', extraClassName), 'aria-label': label, skeleton, disabled, onClick: event => clickHandler({ pageNumber, event }), children: String(pageNumber) }) }, pageNumber); }; const renderStepButton = direction => { const isPrev = direction === 'prev'; const isDisabled = isPrev ? prevIsDisabled : nextIsDisabled; const title = isPrev ? prevTitle : nextTitle; const icon = isPrev ? 'chevron_left' : 'chevron_right'; const onNavigate = isPrev ? setPrevPage : setNextPage; if (!transformNavigationItem) { return _jsx(Button, { disabled: disabled || isDisabled, skeleton: skeleton, variant: "tertiary", icon: icon, iconPosition: isPrev ? 'left' : 'right', text: title, onClick: onNavigate, title: isDisabled ? null : title }, `${direction}-arrow`); } if (isDisabled) { return null; } const pageNumber = currentPageInternal + (isPrev ? -1 : 1); return _jsx(Fragment, { children: transformNavigationItem(pageNumber, { className: clsx('dnb-pagination__button', `dnb-pagination__button--${direction}`), 'aria-label': title, title, skeleton, disabled, onClick: event => onNavigate(event), children: _jsx(IconPrimary, { icon: icon }) }) }, `${direction}-arrow`); }; return _jsxs("div", { ref: paginationBarRef, ...useSpacing({ space }, { className: clsx('dnb-pagination__bar', pageCountInternal >= 8 && 'dnb-pagination--many-pages') }), children: [_jsxs("div", { className: "dnb-pagination__bar__wrapper", children: [!transformNavigationItem && _jsxs("div", { className: "dnb-pagination__bar__skip", children: [renderStepButton('prev'), renderStepButton('next')] }), _jsxs("div", { className: "dnb-pagination__bar__inner", children: [transformNavigationItem && renderStepButton('prev'), (pageNumberGroups?.[0] || []).map(pageNumber => renderPaginationButton(pageNumber)), pageNumberGroups.slice(1).map((numbersList, idx) => _jsxs(Fragment, { children: [_jsx(IconPrimary, { role: "separator", "aria-orientation": "vertical", "aria-hidden": false, title: getDotsAriaLabel({ morePages, numbersList, pageNumberGroups }), className: "dnb-pagination__dots", icon: "more", size: "medium" }), numbersList.map(pageNumber => renderPaginationButton(pageNumber, String(pageNumber).length > 3 ? 'dnb-pagination__button--large-number' : undefined))] }, idx)), transformNavigationItem && renderStepButton('next')] })] }), _jsx("span", { className: "dnb-sr-only", "aria-live": "assertive", children: buttonTitle.replace('%s', String(currentPageInternal)) })] }); }; export const useResizeObserver = element => { const [currentSize, setSize] = useState('large'); const resizeObserver = useRef(null); useEffect(() => { try { const handleSizeChange = width => { if (width <= getSizeInPx('small') && currentSize !== 'small') { setSize('small'); } else if (width <= getSizeInPx('medium') && currentSize !== 'medium') { setSize('medium'); } else if (width <= getSizeInPx('large') && currentSize !== 'large') { setSize('large'); } else if (width <= getSizeInPx('x-large') && currentSize !== 'x-large') { setSize('x-large'); } else if (width <= getSizeInPx('xx-large') && currentSize !== 'xx-large') { setSize('xx-large'); } }; resizeObserver.current = new ResizeObserver(entries => { handleSizeChange(entries[0].contentRect.width); }); resizeObserver.current?.observe(element.current); handleSizeChange(element.current.clientWidth); } catch (e) {} return () => { resizeObserver.current?.disconnect(); }; }, [element]); return currentSize; }; const getSizeInPx = size => { const styleSize = styleProperties[`--layout-${size}`]; if (_includesInstanceProperty(styleSize).call(styleSize, 'em')) { return parseFloat(styleSize.replace(/(rem|em)$/, '')) * 16; } return parseFloat(styleSize.replace(/(px)$/, '')); }; withComponentMarkers(PaginationBar, { _supportsSpacingProps: true }); export default PaginationBar; //# sourceMappingURL=PaginationBar.js.map