1
- import Calendar from " ./calendar" ;
2
- import React from " react" ;
3
- import PropTypes from " prop-types" ;
4
- import PopperComponent , { popperPlacementPositions } from " ./popper_component" ;
5
- import classnames from " classnames" ;
1
+ import Calendar from ' ./calendar' ;
2
+ import React from ' react' ;
3
+ import PropTypes from ' prop-types' ;
4
+ import PopperComponent , { popperPlacementPositions } from ' ./popper_component' ;
5
+ import classnames from ' classnames' ;
6
6
import {
7
7
newDate ,
8
8
now ,
@@ -34,13 +34,13 @@ import {
34
34
safeDateFormat ,
35
35
getHightLightDaysMap ,
36
36
getYear ,
37
- getMonth
38
- } from " ./date_utils" ;
39
- import onClickOutside from " react-onclickoutside" ;
37
+ getMonth ,
38
+ } from ' ./date_utils' ;
39
+ import onClickOutside from ' react-onclickoutside' ;
40
40
41
- export { default as CalendarContainer } from " ./calendar_container" ;
41
+ export { default as CalendarContainer } from ' ./calendar_container' ;
42
42
43
- const outsideClickIgnoreClass = " react-datepicker-ignore-onclickoutside" ;
43
+ const outsideClickIgnoreClass = ' react-datepicker-ignore-onclickoutside' ;
44
44
const WrappedCalendar = onClickOutside ( Calendar ) ;
45
45
46
46
// Compares dates year+month combinations
@@ -65,6 +65,7 @@ function hasSelectionChanged(date1, date2) {
65
65
/**
66
66
* General datepicker component.
67
67
*/
68
+ const INPUT_ERR_1 = 'Date input not valid.' ;
68
69
69
70
export default class DatePicker extends React . Component {
70
71
static propTypes = {
@@ -84,7 +85,7 @@ export default class DatePicker extends React.Component {
84
85
dayClassName : PropTypes . func ,
85
86
disabled : PropTypes . bool ,
86
87
disabledKeyboardNavigation : PropTypes . bool ,
87
- dropdownMode : PropTypes . oneOf ( [ " scroll" , " select" ] ) . isRequired ,
88
+ dropdownMode : PropTypes . oneOf ( [ ' scroll' , ' select' ] ) . isRequired ,
88
89
endDate : PropTypes . object ,
89
90
excludeDates : PropTypes . array ,
90
91
filterDate : PropTypes . func ,
@@ -113,6 +114,7 @@ export default class DatePicker extends React.Component {
113
114
onKeyDown : PropTypes . func ,
114
115
onMonthChange : PropTypes . func ,
115
116
onYearChange : PropTypes . func ,
117
+ onInputError : PropTypes . func ,
116
118
open : PropTypes . bool ,
117
119
openToDate : PropTypes . object ,
118
120
peekNextMonth : PropTypes . bool ,
@@ -166,12 +168,12 @@ export default class DatePicker extends React.Component {
166
168
static get defaultProps ( ) {
167
169
return {
168
170
allowSameDay : false ,
169
- dateFormat : "L" ,
170
- dateFormatCalendar : " MMMM YYYY" ,
171
+ dateFormat : 'L' ,
172
+ dateFormatCalendar : ' MMMM YYYY' ,
171
173
onChange ( ) { } ,
172
174
disabled : false ,
173
175
disabledKeyboardNavigation : false ,
174
- dropdownMode : " scroll" ,
176
+ dropdownMode : ' scroll' ,
175
177
onFocus ( ) { } ,
176
178
onBlur ( ) { } ,
177
179
onKeyDown ( ) { } ,
@@ -181,15 +183,16 @@ export default class DatePicker extends React.Component {
181
183
onMonthChange ( ) { } ,
182
184
preventOpenOnFocus : false ,
183
185
onYearChange ( ) { } ,
186
+ onInputError ( ) { } ,
184
187
monthsShown : 1 ,
185
188
readOnly : false ,
186
189
withPortal : false ,
187
190
shouldCloseOnSelect : true ,
188
191
showTimeSelect : false ,
189
192
timeIntervals : 30 ,
190
- timeCaption : " Time" ,
191
- previousMonthButtonLabel : " Previous Month" ,
192
- nextMonthButtonLabel : " Next month"
193
+ timeCaption : ' Time' ,
194
+ previousMonthButtonLabel : ' Previous Month' ,
195
+ nextMonthButtonLabel : ' Next month' ,
193
196
} ;
194
197
}
195
198
@@ -207,7 +210,7 @@ export default class DatePicker extends React.Component {
207
210
}
208
211
if ( prevProps . highlightDates !== this . props . highlightDates ) {
209
212
this . setState ( {
210
- highlightDates : getHightLightDaysMap ( this . props . highlightDates )
213
+ highlightDates : getHightLightDaysMap ( this . props . highlightDates ) ,
211
214
} ) ;
212
215
}
213
216
if (
@@ -250,7 +253,7 @@ export default class DatePicker extends React.Component {
250
253
// transforming highlighted days (perhaps nested array)
251
254
// to flat Map for faster access in day.jsx
252
255
highlightDates : getHightLightDaysMap ( this . props . highlightDates ) ,
253
- focused : false
256
+ focused : false ,
254
257
} ;
255
258
} ;
256
259
@@ -273,9 +276,11 @@ export default class DatePicker extends React.Component {
273
276
open && this . state . open
274
277
? this . state . preSelection
275
278
: this . calcInitialState ( ) . preSelection ,
276
- lastPreSelectChange : PRESELECT_CHANGE_VIA_NAVIGATE
279
+ lastPreSelectChange : PRESELECT_CHANGE_VIA_NAVIGATE ,
277
280
} ) ;
278
281
} ;
282
+ inputOk = ( ) =>
283
+ isMoment ( this . state . preSelection ) || isDate ( this . state . preSelection ) ;
279
284
280
285
isCalendarOpen = ( ) =>
281
286
this . props . open === undefined
@@ -330,15 +335,15 @@ export default class DatePicker extends React.Component {
330
335
if ( this . props . onChangeRaw ) {
331
336
this . props . onChangeRaw . apply ( this , allArgs ) ;
332
337
if (
333
- typeof event . isDefaultPrevented !== " function" ||
338
+ typeof event . isDefaultPrevented !== ' function' ||
334
339
event . isDefaultPrevented ( )
335
340
) {
336
341
return ;
337
342
}
338
343
}
339
344
this . setState ( {
340
345
inputValue : event . target . value ,
341
- lastPreSelectChange : PRESELECT_CHANGE_VIA_INPUT
346
+ lastPreSelectChange : PRESELECT_CHANGE_VIA_INPUT ,
342
347
} ) ;
343
348
const date = parseDate ( event . target . value , this . props ) ;
344
349
if ( date || ! event . target . value ) {
@@ -352,7 +357,7 @@ export default class DatePicker extends React.Component {
352
357
this . setState ( { preventFocus : true } , ( ) => {
353
358
this . preventFocusTimeout = setTimeout (
354
359
( ) => this . setState ( { preventFocus : false } ) ,
355
- 50
360
+ 50 ,
356
361
) ;
357
362
return this . preventFocusTimeout ;
358
363
} ) ;
@@ -391,12 +396,12 @@ export default class DatePicker extends React.Component {
391
396
changedDate = setTime ( newDate ( changedDate ) , {
392
397
hour : getHour ( selected ) ,
393
398
minute : getMinute ( selected ) ,
394
- second : getSecond ( selected )
399
+ second : getSecond ( selected ) ,
395
400
} ) ;
396
401
}
397
402
if ( ! this . props . inline ) {
398
403
this . setState ( {
399
- preSelection : changedDate
404
+ preSelection : changedDate ,
400
405
} ) ;
401
406
}
402
407
}
@@ -412,15 +417,15 @@ export default class DatePicker extends React.Component {
412
417
413
418
setPreSelection = date => {
414
419
const isDateRangePresent =
415
- typeof this . props . minDate !== " undefined" &&
416
- typeof this . props . maxDate !== " undefined" ;
420
+ typeof this . props . minDate !== ' undefined' &&
421
+ typeof this . props . maxDate !== ' undefined' ;
417
422
const isValidDateSelection =
418
423
isDateRangePresent && date
419
424
? isDayInRange ( date , this . props . minDate , this . props . maxDate )
420
425
: true ;
421
426
if ( isValidDateSelection ) {
422
427
this . setState ( {
423
- preSelection : date
428
+ preSelection : date ,
424
429
} ) ;
425
430
}
426
431
} ;
@@ -431,11 +436,11 @@ export default class DatePicker extends React.Component {
431
436
: this . getPreSelection ( ) ;
432
437
let changedDate = setTime ( cloneDate ( selected ) , {
433
438
hour : getHour ( time ) ,
434
- minute : getMinute ( time )
439
+ minute : getMinute ( time ) ,
435
440
} ) ;
436
441
437
442
this . setState ( {
438
- preSelection : changedDate
443
+ preSelection : changedDate ,
439
444
} ) ;
440
445
441
446
this . props . onChange ( changedDate ) ;
@@ -459,17 +464,16 @@ export default class DatePicker extends React.Component {
459
464
! this . props . inline &&
460
465
! this . props . preventOpenOnFocus
461
466
) {
462
- if ( eventKey === " ArrowDown" || eventKey === " ArrowUp" ) {
467
+ if ( eventKey === ' ArrowDown' || eventKey === ' ArrowUp' ) {
463
468
this . onInputClick ( ) ;
464
469
}
465
470
return ;
466
471
}
467
472
const copy = newDate ( this . state . preSelection ) ;
468
- if ( eventKey === " Enter" ) {
473
+ if ( eventKey === ' Enter' ) {
469
474
event . preventDefault ( ) ;
470
475
if (
471
- ( isMoment ( this . state . preSelection ) ||
472
- isDate ( this . state . preSelection ) ) &&
476
+ this . inputOk ( ) &&
473
477
this . state . lastPreSelectChange === PRESELECT_CHANGE_VIA_NAVIGATE
474
478
) {
475
479
this . handleSelect ( copy , event ) ;
@@ -481,45 +485,53 @@ export default class DatePicker extends React.Component {
481
485
482
486
this . setOpen ( false ) ;
483
487
}
484
- } else if ( eventKey === " Escape" ) {
488
+ } else if ( eventKey === ' Escape' ) {
485
489
event . preventDefault ( ) ;
486
490
487
491
this . input . blur ( ) ;
488
492
this . props . onBlur ( copy ) ;
489
493
this . cancelFocusInput ( ) ;
490
494
491
495
this . setOpen ( false ) ;
492
- } else if ( eventKey === "Tab" ) {
496
+ if ( ! this . inputOk ( ) ) {
497
+ this . props . onInputError ( { code : 1 , msg : INPUT_ERR_1 } ) ;
498
+ }
499
+ } else if ( eventKey === 'Tab' ) {
493
500
this . setOpen ( false ) ;
494
501
} else if ( ! this . props . disabledKeyboardNavigation ) {
495
502
let newSelection ;
496
503
switch ( eventKey ) {
497
- case " ArrowLeft" :
504
+ case ' ArrowLeft' :
498
505
newSelection = subtractDays ( copy , 1 ) ;
499
506
break ;
500
- case " ArrowRight" :
507
+ case ' ArrowRight' :
501
508
newSelection = addDays ( copy , 1 ) ;
502
509
break ;
503
- case " ArrowUp" :
510
+ case ' ArrowUp' :
504
511
newSelection = subtractWeeks ( copy , 1 ) ;
505
512
break ;
506
- case " ArrowDown" :
513
+ case ' ArrowDown' :
507
514
newSelection = addWeeks ( copy , 1 ) ;
508
515
break ;
509
- case " PageUp" :
516
+ case ' PageUp' :
510
517
newSelection = subtractMonths ( copy , 1 ) ;
511
518
break ;
512
- case " PageDown" :
519
+ case ' PageDown' :
513
520
newSelection = addMonths ( copy , 1 ) ;
514
521
break ;
515
- case " Home" :
522
+ case ' Home' :
516
523
newSelection = subtractYears ( copy , 1 ) ;
517
524
break ;
518
- case " End" :
525
+ case ' End' :
519
526
newSelection = addYears ( copy , 1 ) ;
520
527
break ;
521
528
}
522
- if ( ! newSelection ) return ; // Let the input component handle this keydown
529
+ if ( ! newSelection ) {
530
+ if ( this . props . onInputError ) {
531
+ this . props . onInputError ( { code : 1 , msg : INPUT_ERR_1 } ) ;
532
+ }
533
+ return ; // Let the input component handle this keydown
534
+ }
523
535
event . preventDefault ( ) ;
524
536
this . setState ( { lastPreSelectChange : PRESELECT_CHANGE_VIA_NAVIGATE } ) ;
525
537
if ( this . props . adjustDateOnChange ) {
@@ -628,11 +640,11 @@ export default class DatePicker extends React.Component {
628
640
} ) ;
629
641
630
642
const customInput = this . props . customInput || < input type = "text" /> ;
631
- const customInputRef = this . props . customInputRef || " ref" ;
643
+ const customInputRef = this . props . customInputRef || ' ref' ;
632
644
const inputValue =
633
- typeof this . props . value === " string"
645
+ typeof this . props . value === ' string'
634
646
? this . props . value
635
- : typeof this . state . inputValue === " string"
647
+ : typeof this . state . inputValue === ' string'
636
648
? this . state . inputValue
637
649
: safeDateFormat ( this . props . selected , this . props ) ;
638
650
@@ -656,7 +668,7 @@ export default class DatePicker extends React.Component {
656
668
title : this . props . title ,
657
669
readOnly : this . props . readOnly ,
658
670
required : this . props . required ,
659
- tabIndex : this . props . tabIndex
671
+ tabIndex : this . props . tabIndex ,
660
672
} ) ;
661
673
} ;
662
674
@@ -718,5 +730,5 @@ export default class DatePicker extends React.Component {
718
730
}
719
731
}
720
732
721
- const PRESELECT_CHANGE_VIA_INPUT = " input" ;
722
- const PRESELECT_CHANGE_VIA_NAVIGATE = " navigate" ;
733
+ const PRESELECT_CHANGE_VIA_INPUT = ' input' ;
734
+ const PRESELECT_CHANGE_VIA_NAVIGATE = ' navigate' ;
0 commit comments