@@ -126,61 +126,122 @@ function PaginationPageHandler<P extends string | number>({
126126 setCurrentPage ( pages [ currentPageIndex ] )
127127 }
128128
129- const visiblePages = useMemo ( ( ) => {
130- const halfMaxPageButtons = Math . floor ( maxPageButtons / 2 )
131- if ( pages . length <= maxPageButtons ) return pages
132- const _currentIndex = pages . indexOf ( _currentPage )
129+ const { visiblePages, currentIndex } = useMemo ( ( ) => {
130+ const currentIndex = currentPageIndex ?? pages . indexOf ( _currentPage )
131+ const halfMaxPageButtons = Math . ceil ( maxPageButtons / 2 )
132+ if ( pages . length <= maxPageButtons )
133+ return { visiblePages : pages , currentIndex }
133134
134- let ret : ( P | string ) [ ] = [ ]
135-
136- if ( _currentIndex < halfMaxPageButtons ) {
137- ret = pages . slice ( 0 , maxPageButtons )
138- if ( maxPageButtons >= 5 && pages . length > maxPageButtons ) {
139- ret [ maxPageButtons - 2 ] = "..."
140- ret [ maxPageButtons - 1 ] = pages [ pages . length - 1 ]
141- }
142- } else if ( _currentIndex > pages . length - halfMaxPageButtons ) {
143- ret = pages . slice ( pages . length - maxPageButtons )
144- if ( maxPageButtons >= 5 && pages . length > maxPageButtons ) {
145- ret [ 1 ] = "..."
146- ret [ 0 ] = pages [ 0 ]
147- }
148- } else {
149- let start = _currentIndex - halfMaxPageButtons
150- let addEnd = true
151- if ( start >= pages . length - maxPageButtons ) {
152- start = pages . length - maxPageButtons
153- addEnd = false
154- }
155- ret = pages . slice ( start , start + maxPageButtons )
156- if ( addEnd ) {
157- if ( maxPageButtons >= 5 && pages . length > maxPageButtons ) {
158- ret [ ret . length - 2 ] = "..."
159- ret [ ret . length - 1 ] = pages [ pages . length - 1 ]
160- }
161- }
162- if ( start > 0 ) {
163- if ( maxPageButtons >= 5 && pages . length > maxPageButtons ) {
164- ret [ 1 ] = "..."
165- ret [ 0 ] = pages [ 0 ]
166- }
167- }
135+ const ret : ( P | string ) [ ] = [ ]
136+ for (
137+ let i = currentIndex ;
138+ i < currentIndex + halfMaxPageButtons && i < pages . length ;
139+ i ++
140+ ) {
141+ ret . push ( pages [ i ] )
142+ }
143+ for (
144+ let i = currentIndex - 1 ;
145+ i >= 0 &&
146+ i >= currentIndex - maxPageButtons &&
147+ ret . length < maxPageButtons ;
148+ i --
149+ ) {
150+ ret . unshift ( pages [ i ] )
151+ }
152+ for ( let i = ret . length ; i < maxPageButtons && i < pages . length ; i ++ ) {
153+ ret . push ( pages [ i ] )
168154 }
169155
170- return ret
171- } , [ _currentPage , maxPageButtons , pages ] )
156+ // ellipsis logic
157+ if ( ret [ 1 ] !== pages [ 1 ] ) {
158+ ret [ 1 ] = "..."
159+ ret [ 0 ] = pages [ 0 ]
160+ }
161+ if ( ret [ ret . length - 2 ] !== pages [ pages . length - 2 ] ) {
162+ ret [ ret . length - 2 ] = "..."
163+ ret [ ret . length - 1 ] = pages [ pages . length - 1 ]
164+ }
165+ return { visiblePages : ret , currentIndex }
166+ } , [ _currentPage , maxPageButtons , pages , currentPageIndex ] )
172167
173- const currentIdx = pages . indexOf ( _currentPage )
168+ const pageButtons = useMemo ( ( ) => {
169+ let ellipsisCountUsed = 0
170+ return visiblePages . map ( ( page , i ) => {
171+ if ( page === "..." ) {
172+ ellipsisCountUsed ++
173+ }
174+ return (
175+ < li
176+ key = { page . toString ( ) + i }
177+ aria-hidden = { page === "..." }
178+ className = "m-0"
179+ >
180+ { page !== "..." ? (
181+ < button
182+ className = { twMerge (
183+ "flex cursor-pointer h-8 min-w-8 select-none items-center justify-center rounded-xs p-1.5 border-0 border-none border-transparent bg-transparent" ,
184+ "data-[current=true]:bg-selected data-[current=true]:text-selected-text-inverse data-[current=true]:cursor-default" ,
185+ "hover:bg-neutral-hovered active:bg-neutral-pressed" ,
186+ pageButtonClassName ,
187+ ) }
188+ onClick = { ( ) => {
189+ const currentIndex = pages . indexOf ( page as P )
190+ setCurrentPage ( page as P )
191+ onPageIndexChange ?.( currentIndex )
192+ onPageChange ?.( page as P )
193+ } }
194+ onKeyUp = { ( e ) => {
195+ if ( e . key === "Enter" ) {
196+ const currentIndex = pages . indexOf (
197+ page as P ,
198+ )
199+ setCurrentPage ( page as P )
200+ onPageIndexChange ?.( currentIndex )
201+ onPageChange ?.( page as P )
202+ }
203+ } }
204+ aria-label = { `${ pageLabel } ${ page } ` }
205+ type = "button"
206+ aria-current = {
207+ page === _currentPage ? "page" : undefined
208+ }
209+ style = { pageButtonStyle }
210+ data-current = { page === _currentPage }
211+ >
212+ { page }
213+ </ button >
214+ ) : (
215+ < div
216+ className = "flex h-8 w-8 select-none items-center justify-center rounded-xs p-1.5"
217+ aria-hidden = "true"
218+ >
219+ ...
220+ </ div >
221+ ) }
222+ </ li >
223+ )
224+ } )
225+ } , [
226+ visiblePages ,
227+ pageButtonClassName ,
228+ pageButtonStyle ,
229+ pageLabel ,
230+ _currentPage ,
231+ pages ,
232+ onPageIndexChange ,
233+ onPageChange ,
234+ ] )
174235
175236 return (
176237 < nav className = { className } style = { style } aria-label = { label } >
177238 < ul className = "flex list-none items-center" >
178239 < li className = "m-0" >
179240 < button
180- disabled = { currentIdx <= 0 }
241+ disabled = { currentIndex <= 0 }
181242 className = { twMerge (
182243 `flex cursor-pointer disabled:cursor-default h-8 w-8 select-none items-center justify-center rounded p-1.5 border-0 border-none border-transparent bg-transparent ${
183- currentIdx > 0
244+ currentIndex > 0
184245 ? "hover:bg-neutral-hovered active:bg-neutral-pressed text-text"
185246 : "text-disabled-text"
186247 } `,
@@ -194,68 +255,20 @@ function PaginationPageHandler<P extends string | number>({
194255 } }
195256 title = { previousLabel }
196257 aria-label = { previousLabel }
197- aria-disabled = { currentIdx >= pages . length - 1 }
258+ aria-disabled = { currentIndex >= pages . length - 1 }
198259 type = "button"
199260 >
200261 < IconSizeHelper >
201262 < ChevronLeftIcon size = "16" aria-label = "page left" />
202263 </ IconSizeHelper >
203264 </ button >
204265 </ li >
205- { visiblePages . map ( ( page ) => (
206- < li key = { page } aria-hidden = { page === "..." } className = "m-0" >
207- { page !== "..." ? (
208- < button
209- className = { twMerge (
210- "flex cursor-pointer h-8 min-w-8 select-none items-center justify-center rounded-xs p-1.5 border-0 border-none border-transparent bg-transparent" ,
211- "data-[current=true]:bg-selected data-[current=true]:text-selected-text-inverse data-[current=true]:cursor-default" ,
212- "hover:bg-neutral-hovered active:bg-neutral-pressed" ,
213- pageButtonClassName ,
214- ) }
215- onClick = { ( ) => {
216- const currentIndex = pages . indexOf (
217- page as P ,
218- )
219- setCurrentPage ( page as P )
220- onPageIndexChange ?.( currentIndex )
221- onPageChange ?.( page as P )
222- } }
223- onKeyUp = { ( e ) => {
224- if ( e . key === "Enter" ) {
225- const currentIndex = pages . indexOf (
226- page as P ,
227- )
228- setCurrentPage ( page as P )
229- onPageIndexChange ?.( currentIndex )
230- onPageChange ?.( page as P )
231- }
232- } }
233- aria-label = { `${ pageLabel } ${ page } ` }
234- type = "button"
235- aria-current = {
236- page === _currentPage ? "page" : undefined
237- }
238- style = { pageButtonStyle }
239- data-current = { page === _currentPage }
240- >
241- { page }
242- </ button >
243- ) : (
244- < div
245- key = { page }
246- className = "flex h-8 w-8 select-none items-center justify-center rounded-xs p-1.5"
247- aria-hidden = "true"
248- >
249- { page } { /* is "..." */ }
250- </ div >
251- ) }
252- </ li >
253- ) ) }
266+ { pageButtons }
254267 < li className = "m-0" >
255268 < button
256269 className = { twMerge (
257270 `flex cursor-pointer disabled:cursor-default h-8 w-8 select-none items-center justify-center rounded p-1.5 bg-transparent border-none border-0 border-transparent ${
258- currentIdx < pages . length - 1
271+ currentIndex < pages . length - 1
259272 ? "hover:bg-neutral-hovered active:bg-neutral-pressed text-text"
260273 : "text-disabled-text"
261274 } `,
@@ -267,10 +280,10 @@ function PaginationPageHandler<P extends string | number>({
267280 onPageIndexChange ?.( _currentIndex + 1 )
268281 onPageChange ?.( pages [ _currentIndex + 1 ] )
269282 } }
270- disabled = { currentIdx >= pages . length - 1 }
283+ disabled = { currentIndex >= pages . length - 1 }
271284 title = { nextLabel }
272285 aria-label = { nextLabel }
273- aria-disabled = { currentIdx >= pages . length - 1 }
286+ aria-disabled = { currentIndex >= pages . length - 1 }
274287 type = "button"
275288 style = { pageButtonStyle }
276289 >
0 commit comments