@@ -10,10 +10,8 @@ import {
1010 Pagination ,
1111 PaginationContent ,
1212 PaginationItem ,
13- PaginationLink ,
1413 PaginationPrevious ,
1514 PaginationNext ,
16- PaginationEllipsis ,
1715} from '@/components/auth0/shared/pagination' ;
1816import {
1917 Select ,
@@ -44,12 +42,12 @@ export const defaultLabels: DataPaginationLabels = {
4442 showing : 'Showing' ,
4543 to : 'to' ,
4644 of : 'of' ,
47- results : 'results ' ,
45+ results : '' ,
4846 totalResults : 'total results' ,
49- show : 'Show ' ,
47+ show : '' ,
5048 perPage : 'per page' ,
51- previous : 'Previous ' ,
52- next : 'Next ' ,
49+ previous : '' ,
50+ next : '' ,
5351 goToPage : 'Go to page {page}' ,
5452 goToPrevious : 'Go to previous page' ,
5553 goToNext : 'Go to next page' ,
@@ -66,6 +64,7 @@ export interface RegularPaginationState {
6664
6765export interface CheckpointPaginationState {
6866 pageSize : number ;
67+ currentPage ?: number ;
6968 totalItems ?: number ;
7069 hasNextPage : boolean ;
7170 hasPreviousPage : boolean ;
@@ -86,6 +85,14 @@ export interface DataPaginationProps {
8685 onPreviousPage ?: ( ) => void ;
8786}
8887
88+ interface PageRangeInfoProps {
89+ totalItems : number ;
90+ currentPage : number ;
91+ pageSize : number ;
92+ locale ?: string ;
93+ labels : DataPaginationLabels ;
94+ }
95+
8996const formatNumber = ( num : number | undefined | null , locale ?: string ) : string => {
9097 if ( num === null || num === undefined || isNaN ( num ) ) {
9198 return '0' ;
@@ -96,32 +103,46 @@ const formatNumber = (num: number | undefined | null, locale?: string): string =
96103 return num . toLocaleString ( resolvedLocale ) ;
97104} ;
98105
99- const interpolate = ( str : string , values : Record < string , string | number > ) : string =>
100- str . replace ( / \{ ( \w + ) \} / g, ( _ , key ) => String ( values [ key ] ?? '' ) ) ;
101-
102- const generatePageNumbers = (
106+ const getPageRange = (
107+ totalItems : number ,
103108 currentPage : number ,
104- totalPages : number ,
105- maxVisible : number = 5 ,
106- ) : ( number | 'ellipsis' ) [ ] => {
107- if ( totalPages <= maxVisible ) return Array . from ( { length : totalPages } , ( _ , i ) => i + 1 ) ;
108-
109- const pages : ( number | 'ellipsis' ) [ ] = [ 1 ] ;
110- const range = Math . floor ( ( maxVisible - 3 ) / 2 ) ;
111- let start = Math . max ( 2 , currentPage - range ) ;
112- let end = Math . min ( totalPages - 1 , currentPage + range ) ;
113-
114- if ( currentPage <= range + 2 ) end = maxVisible - 2 ;
115- if ( currentPage >= totalPages - range - 1 ) start = totalPages - ( maxVisible - 2 ) ;
116-
117- if ( start > 2 ) pages . push ( 'ellipsis' ) ;
118- for ( let i = start ; i <= end ; i ++ ) pages . push ( i ) ;
119- if ( end < totalPages - 1 ) pages . push ( 'ellipsis' ) ;
120- pages . push ( totalPages ) ;
121-
122- return pages ;
109+ pageSize : number ,
110+ locale ?: string ,
111+ ) : { start : string ; end : string } => {
112+ const start = totalItems === 0 ? 0 : ( currentPage - 1 ) * pageSize + 1 ;
113+ const end = Math . min ( currentPage * pageSize , totalItems ) ;
114+ return {
115+ start : formatNumber ( start , locale ) ,
116+ end : formatNumber ( end , locale ) ,
117+ } ;
123118} ;
124119
120+ /**
121+ * Renders the page range info.
122+ *
123+ * @param props - Component props.
124+ * @param props.totalItems - Total number of items.
125+ * @param props.currentPage - Current page number.
126+ * @param props.pageSize - Number of items per page.
127+ * @param props.locale - Locale identifier for number formatting.
128+ * @param props.labels - Label text configuration.
129+ * @returns JSX element displaying the page range info.
130+ */
131+ function PageRangeInfo ( { totalItems, currentPage, pageSize, locale, labels } : PageRangeInfoProps ) {
132+ const range = getPageRange ( totalItems , currentPage , pageSize , locale ) ;
133+ return (
134+ < >
135+ { labels . showing } { ' ' }
136+ < span className = "font-medium text-foreground" >
137+ { range . start } -{ range . end }
138+ </ span > { ' ' }
139+ { labels . of } { ' ' }
140+ < span className = "font-medium text-foreground" > { formatNumber ( totalItems , locale ) } </ span >
141+ { labels . results && < > { labels . results } </ > }
142+ </ >
143+ ) ;
144+ }
145+
125146/**
126147 *
127148 * @param props - Component props.
@@ -170,18 +191,6 @@ export function DataPagination({
170191 return Array . from ( uniqueOptions ) . sort ( ( a , b ) => a - b ) ;
171192 } , [ shouldShowPageSizeSelector , pageSizeOptions , currentPageSize ] ) ;
172193
173- const pageNumbers = useMemo (
174- ( ) =>
175- isRegular && regularState
176- ? generatePageNumbers (
177- regularState . currentPage ,
178- regularState . totalPages ,
179- regularState . maxVisiblePages ,
180- )
181- : [ ] ,
182- [ isRegular , regularState ] ,
183- ) ;
184-
185194 useEffect ( ( ) => {
186195 if ( ariaLiveRegionRef . current ) {
187196 if ( isRegular && regularState ) {
@@ -196,7 +205,6 @@ export function DataPagination({
196205 return null ;
197206 }
198207
199- const shouldShowPageNumbers = isRegular ;
200208 const safeCurrentPageSize = currentPageSize as number ;
201209
202210 return (
@@ -214,32 +222,22 @@ export function DataPagination({
214222 { showPageInfo && (
215223 < div className = "text-sm text-foreground whitespace-nowrap sm:mr-auto" >
216224 { isRegular && regularState ? (
217- < >
218- { labels . showing } { ' ' }
219- < span className = "font-medium text-foreground" >
220- { formatNumber (
221- regularState . totalItems === 0
222- ? 0
223- : ( regularState . currentPage - 1 ) * regularState . pageSize + 1 ,
224- locale ,
225- ) }
226- </ span > { ' ' }
227- { labels . to } { ' ' }
228- < span className = "font-medium text-foreground" >
229- { formatNumber (
230- Math . min (
231- regularState . currentPage * regularState . pageSize ,
232- regularState . totalItems ,
233- ) ,
234- locale ,
235- ) }
236- </ span > { ' ' }
237- { labels . of } { ' ' }
238- < span className = "font-medium text-foreground" >
239- { formatNumber ( regularState . totalItems , locale ) }
240- </ span > { ' ' }
241- { labels . results }
242- </ >
225+ < PageRangeInfo
226+ totalItems = { regularState . totalItems }
227+ currentPage = { regularState . currentPage }
228+ pageSize = { regularState . pageSize }
229+ locale = { locale }
230+ labels = { labels }
231+ />
232+ ) : checkpointState ?. totalItems !== undefined &&
233+ checkpointState ?. currentPage !== undefined ? (
234+ < PageRangeInfo
235+ totalItems = { checkpointState . totalItems }
236+ currentPage = { checkpointState . currentPage }
237+ pageSize = { checkpointState . pageSize }
238+ locale = { locale }
239+ labels = { labels }
240+ />
243241 ) : checkpointState ?. totalItems !== undefined ? (
244242 < >
245243 < span className = "font-medium text-foreground" >
@@ -254,7 +252,7 @@ export function DataPagination({
254252 < div className = "flex flex-col gap-4 sm:flex-row sm:items-center" >
255253 { shouldShowPageSizeSelector && allPageSizeOptions . length > 0 && (
256254 < div className = "flex items-center justify-center gap-2 whitespace-nowrap sm:justify-start" >
257- < span className = "text-sm text-foreground" > { labels . show } </ span >
255+ { labels . show && < span className = "text-sm text-foreground" > { labels . show } </ span > }
258256 < Select
259257 value = { safeCurrentPageSize . toString ( ) }
260258 onValueChange = { ( value ) => onPageSizeChange ?.( Number ( value ) ) }
@@ -291,28 +289,6 @@ export function DataPagination({
291289 />
292290 </ PaginationItem >
293291
294- { shouldShowPageNumbers &&
295- pageNumbers . map ( ( page , idx ) => (
296- < PaginationItem key = { `page-${ idx } ` } >
297- { page === 'ellipsis' ? (
298- < PaginationEllipsis >
299- < span className = "sr-only" > { labels . morePages } </ span >
300- </ PaginationEllipsis >
301- ) : (
302- < PaginationLink
303- onClick = { ( ) => onPageChange ?.( page ) }
304- isActive = { regularState . currentPage === page }
305- aria-label = { interpolate ( labels . goToPage , {
306- page : formatNumber ( page , locale ) ,
307- } ) }
308- aria-current = { regularState . currentPage === page ? 'page' : undefined }
309- >
310- { formatNumber ( page , locale ) }
311- </ PaginationLink >
312- ) }
313- </ PaginationItem >
314- ) ) }
315-
316292 < PaginationItem >
317293 < PaginationNext
318294 label = { labels . next }
0 commit comments