11'use client' ;
22
33import { Button } from '@headlessui/react' ;
4+ import { useState , useEffect , useRef } from 'react' ;
45
56export const Navigator = ( { currentPage, numPages, skipToLocation } : {
67 currentPage : number ;
78 numPages : number | undefined ;
89 skipToLocation : ( location : string | number , shouldPause ?: boolean ) => void ;
910} ) => {
11+ const [ inputValue , setInputValue ] = useState ( currentPage . toString ( ) ) ;
12+ const inputRef = useRef < HTMLInputElement > ( null ) ;
13+
14+ useEffect ( ( ) => {
15+ setInputValue ( currentPage . toString ( ) ) ;
16+ } , [ currentPage ] ) ;
17+
18+ const handleInputChange = ( e : React . ChangeEvent < HTMLInputElement > ) => {
19+ // Only allow numbers
20+ const value = e . target . value . replace ( / [ ^ 0 - 9 ] / g, '' ) ;
21+ setInputValue ( value ) ;
22+ } ;
23+
24+ const handleInputConfirm = ( ) => {
25+ let page = parseInt ( inputValue , 10 ) ;
26+ if ( isNaN ( page ) ) return ;
27+ const maxPage = numPages || 1 ;
28+ if ( page < 1 ) page = 1 ;
29+ if ( page > maxPage ) page = maxPage ;
30+ if ( page !== currentPage ) {
31+ skipToLocation ( page , true ) ;
32+ } else {
33+ setInputValue ( page . toString ( ) ) ; // reset input if unchanged
34+ }
35+ } ;
36+
37+ const handleInputKeyDown = ( e : React . KeyboardEvent < HTMLInputElement > ) => {
38+ if ( e . key === 'Enter' ) {
39+ handleInputConfirm ( ) ;
40+ inputRef . current ?. blur ( ) ;
41+ }
42+ } ;
43+
1044 return (
1145 < div className = "flex items-center space-x-1" >
1246 { /* Page back */ }
@@ -21,11 +55,21 @@ export const Navigator = ({ currentPage, numPages, skipToLocation }: {
2155 </ svg >
2256 </ Button >
2357
24- { /* Page number */ }
25- < div className = "bg-offbase px-2 py-0.5 rounded-full" >
26- < p className = "text-xs whitespace-nowrap" >
27- { currentPage } / { numPages || 1 }
28- </ p >
58+ { /* Page number input */ }
59+ < div className = "bg-offbase px-2 py-0.5 rounded-full flex items-center" >
60+ < input
61+ ref = { inputRef }
62+ type = "text"
63+ inputMode = "numeric"
64+ pattern = "[0-9]*"
65+ className = "w-8 text-xs text-center bg-transparent outline-none appearance-none"
66+ value = { inputValue }
67+ onChange = { handleInputChange }
68+ onBlur = { handleInputConfirm }
69+ onKeyDown = { handleInputKeyDown }
70+ aria-label = "Page number"
71+ />
72+ < span className = "text-xs ml-1" > / { numPages || 1 } </ span >
2973 </ div >
3074
3175 { /* Page forward */ }
0 commit comments