@@ -29,27 +29,43 @@ const TimePicker = ({ value, setValue, className = "" }) => (
2929 </ div >
3030) ;
3131
32+ const formatDateForInput = ( date ) => {
33+ if ( ! date ) return "" ;
34+ const d = new Date ( date ) ;
35+ const year = d . getFullYear ( ) ;
36+ const month = String ( d . getMonth ( ) + 1 ) . padStart ( 2 , "0" ) ;
37+ const day = String ( d . getDate ( ) ) . padStart ( 2 , "0" ) ;
38+ return `${ year } -${ month } -${ day } ` ;
39+ } ;
40+
3241const DateInput = ( { value, onChange, className = "" } ) => {
33- const formatDateForInput = ( date ) => {
34- if ( ! date ) return "" ;
35- const d = new Date ( date ) ;
36- // Use local date to avoid timezone issues
37- const year = d . getFullYear ( ) ;
38- const month = String ( d . getMonth ( ) + 1 ) . padStart ( 2 , "0" ) ;
39- const day = String ( d . getDate ( ) ) . padStart ( 2 , "0" ) ;
40- return `${ year } -${ month } -${ day } ` ;
41- } ;
42+ const [ inputValue , setInputValue ] = React . useState ( ( ) =>
43+ formatDateForInput ( value )
44+ ) ;
45+ const isFocused = React . useRef ( false ) ;
46+
47+ React . useEffect ( ( ) => {
48+ if ( ! isFocused . current ) {
49+ setInputValue ( formatDateForInput ( value ) ) ;
50+ }
51+ } , [ value ] ) ;
4252
4353 const handleDateChange = ( e ) => {
4454 const dateString = e . target . value ;
55+ setInputValue ( dateString ) ;
56+
4557 if ( ! dateString ) {
4658 onChange ( undefined ) ;
4759 return ;
4860 }
4961
50- // Parse the date string manually to avoid timezone issues
5162 const [ year , month , day ] = dateString . split ( "-" ) . map ( Number ) ;
52- const newDate = new Date ( year , month - 1 , day ) ; // month is 0-indexed
63+
64+ // Browser sends intermediate values like 0002, 0020, 0202 while the user
65+ // is still typing a full year — skip propagating until year is complete.
66+ if ( year < 1000 ) return ;
67+
68+ const newDate = new Date ( year , month - 1 , day ) ;
5369
5470 if ( ! Number . isNaN ( newDate . getTime ( ) ) ) {
5571 onChange ( newDate ) ;
@@ -63,8 +79,15 @@ const DateInput = ({ value, onChange, className = "" }) => {
6379 < input
6480 id = "date-input"
6581 type = "date"
66- value = { formatDateForInput ( value ) }
82+ value = { inputValue }
6783 onChange = { handleDateChange }
84+ onFocus = { ( ) => {
85+ isFocused . current = true ;
86+ } }
87+ onBlur = { ( ) => {
88+ isFocused . current = false ;
89+ setInputValue ( formatDateForInput ( value ) ) ;
90+ } }
6891 className = { cn (
6992 buttonVariants ( { variant : "outline" } ) ,
7093 "form-input text-sm font-medium transition duration-200 ease-in-out" ,
@@ -111,6 +134,10 @@ function Calendar({
111134 onSelect : setSelected ,
112135 ...props
113136} ) {
137+ const [ month , setMonth ] = React . useState < Date > (
138+ selected ? new Date ( selected ) : new Date ( )
139+ ) ;
140+
114141 const [ timeValue , setTimeValue ] = React . useState < string > (
115142 selected
116143 ? `${ new Date ( selected )
@@ -176,6 +203,8 @@ function Calendar({
176203 return ;
177204 }
178205
206+ setMonth ( date ) ;
207+
179208 if ( ! withTime ) {
180209 setSelected ( date ) ;
181210 return ;
@@ -223,12 +252,16 @@ function Calendar({
223252 ) : null ;
224253 } , [ withDateInput , withTime , selected , timeValue ] ) ;
225254
255+ const selectedDate = selected ? new Date ( selected ) : undefined ;
256+
226257 return (
227258 < div >
228259 < DayPicker
229260 mode = "single"
230261 showOutsideDays = { showOutsideDays }
231- selected = { selected }
262+ selected = { selectedDate }
263+ month = { month }
264+ onMonthChange = { setMonth }
232265 onSelect = { handleDaySelect }
233266 captionLayout = { captionLayout }
234267 fromYear = { fromYear }
0 commit comments