11import * as React from 'react' ;
2+ import { useRef , useEffect , useState } from 'react' ;
23import classNames from 'classnames' ;
34import warning from 'rc-util/lib/warning' ;
45import useMergedState from 'rc-util/lib/hooks/useMergedState' ;
@@ -205,13 +206,13 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
205206
206207 const needConfirmButton : boolean = ( picker === 'date' && ! ! showTime ) || picker === 'time' ;
207208
208- const containerRef = React . useRef < HTMLDivElement > ( null ) ;
209- const panelDivRef = React . useRef < HTMLDivElement > ( null ) ;
210- const startInputDivRef = React . useRef < HTMLDivElement > ( null ) ;
211- const endInputDivRef = React . useRef < HTMLDivElement > ( null ) ;
212- const separatorRef = React . useRef < HTMLDivElement > ( null ) ;
213- const startInputRef = React . useRef < HTMLInputElement > ( null ) ;
214- const endInputRef = React . useRef < HTMLInputElement > ( null ) ;
209+ const containerRef = useRef < HTMLDivElement > ( null ) ;
210+ const panelDivRef = useRef < HTMLDivElement > ( null ) ;
211+ const startInputDivRef = useRef < HTMLDivElement > ( null ) ;
212+ const endInputDivRef = useRef < HTMLDivElement > ( null ) ;
213+ const separatorRef = useRef < HTMLDivElement > ( null ) ;
214+ const startInputRef = useRef < HTMLInputElement > ( null ) ;
215+ const endInputRef = useRef < HTMLInputElement > ( null ) ;
215216
216217 // ============================= Misc ==============================
217218 const formatList = toArray ( getDefaultFormat ( format , picker , showTime , use12Hours ) ) ;
@@ -222,7 +223,7 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
222223 } ) ;
223224
224225 // Operation ref
225- const operationRef : React . MutableRefObject < ContextOperationRefProps | null > = React . useRef <
226+ const operationRef : React . MutableRefObject < ContextOperationRefProps | null > = useRef <
226227 ContextOperationRefProps
227228 > ( null ) ;
228229
@@ -270,10 +271,10 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
270271 } ,
271272 } ) ;
272273
273- const [ rangeHoverValue , setRangeHoverValue ] = React . useState < RangeValue < DateType > > ( null ) ;
274+ const [ rangeHoverValue , setRangeHoverValue ] = useState < RangeValue < DateType > > ( null ) ;
274275
275276 // ========================== Hover Range ==========================
276- const [ hoverRangedValue , setHoverRangedValue ] = React . useState < RangeValue < DateType > > ( null ) ;
277+ const [ hoverRangedValue , setHoverRangedValue ] = useState < RangeValue < DateType > > ( null ) ;
277278
278279 const onDateMouseEnter = ( date : DateType ) => {
279280 setHoverRangedValue ( updateValues ( selectedValue , date , mergedActivePickerIndex ) ) ;
@@ -287,7 +288,7 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
287288 value : mode ,
288289 } ) ;
289290
290- React . useEffect ( ( ) => {
291+ useEffect ( ( ) => {
291292 setInnerModes ( [ picker , picker ] ) ;
292293 } , [ picker ] ) ;
293294
@@ -330,34 +331,48 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
330331
331332 // ============================= Popup =============================
332333 // Popup min width
333- const [ popupMinWidth , setPopupMinWidth ] = React . useState ( 0 ) ;
334- React . useEffect ( ( ) => {
334+ const [ popupMinWidth , setPopupMinWidth ] = useState ( 0 ) ;
335+ useEffect ( ( ) => {
335336 if ( ! mergedOpen && containerRef . current ) {
336337 setPopupMinWidth ( containerRef . current . offsetWidth ) ;
337338 }
338339 } , [ mergedOpen ] ) ;
339340
340341 // ============================ Trigger ============================
341- let triggerOpen : ( newOpen : boolean , index : 0 | 1 , preventChangeEvent ?: boolean ) => void ;
342+ // We record opened status here in case repeat open with picker
343+ // - start -> end
344+ // - end -> start
345+ // - start -> end -> not start!
346+ const openRecordsRef = useRef < Record < number , boolean > > ( { } ) ;
342347
343- const triggerChange = (
344- newValue : RangeValue < DateType > ,
345- config : {
346- source ?: 'open' ;
347- forceInput ?: boolean ;
348- } = { } ,
349- ) => {
350- const { forceInput = true , source } = config ;
348+ function triggerOpen ( newOpen : boolean , index : 0 | 1 ) {
349+ if ( newOpen ) {
350+ openRecordsRef . current [ index ] = true ;
351+
352+ setMergedActivePickerIndex ( index ) ;
353+ triggerInnerOpen ( newOpen ) ;
354+
355+ // Open to reset view date
356+ if ( ! mergedOpen ) {
357+ setViewDate ( null , index ) ;
358+ }
359+ } else if ( mergedActivePickerIndex === index ) {
360+ openRecordsRef . current = { } ;
361+ triggerInnerOpen ( newOpen ) ;
362+ }
363+ }
351364
365+ function triggerChange ( newValue : RangeValue < DateType > , sourceIndex : 0 | 1 ) {
352366 let values = newValue ;
353367 const startValue = getValue ( values , 0 ) ;
354368 let endValue = getValue ( values , 1 ) ;
355369
370+ // >>>>> Format start & end values
356371 if ( startValue && endValue && generateConfig . isAfter ( startValue , endValue ) ) {
357372 if (
358373 // WeekPicker only compare week
359374 ( picker === 'week' && ! isSameWeek ( generateConfig , locale . locale , startValue , endValue ) ) ||
360- // WeekPicker only compare week
375+ // QuotaPicker only compare week
361376 ( picker === 'quarter' && ! isSameQuarter ( generateConfig , startValue , endValue ) ) ||
362377 // Other non-TimePicker compare date
363378 ( picker !== 'week' &&
@@ -368,6 +383,9 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
368383 // Clean up end date when start date is after end date
369384 values = [ startValue , null ] ;
370385 endValue = null ;
386+
387+ // Clean up cache since invalidate
388+ openRecordsRef . current = { } ;
371389 } else if ( picker !== 'time' || order !== false ) {
372390 // Reorder when in same date
373391 values = reorderValues ( values , generateConfig ) ;
@@ -389,6 +407,7 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
389407 onCalendarChange ( values , [ startStr , endStr ] ) ;
390408 }
391409
410+ // >>>>> Trigger `onChange` event
392411 const canStartValueTrigger = canValueTrigger ( startValue , 0 , mergedDisabled , allowEmpty ) ;
393412 const canEndValueTrigger = canValueTrigger ( endValue , 1 , mergedDisabled , allowEmpty ) ;
394413
@@ -397,9 +416,6 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
397416 if ( canTrigger ) {
398417 // Trigger onChange only when value is validate
399418 setInnerValue ( values ) ;
400- if ( source !== 'open' ) {
401- triggerOpen ( false , mergedActivePickerIndex , true ) ;
402- }
403419
404420 if (
405421 onChange &&
@@ -408,45 +424,38 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
408424 ) {
409425 onChange ( values , [ startStr , endStr ] ) ;
410426 }
411- } else if ( forceInput ) {
412- // Open miss value panel to force user input
413- const missingValueIndex = canStartValueTrigger ? 1 : 0 ;
427+ }
414428
415- // Same index means user choice to close picker
416- if ( missingValueIndex === mergedActivePickerIndex ) {
417- return ;
418- }
429+ // >>>>> Open picker when
419430
420- if ( source !== 'open' ) {
421- triggerOpen ( true , missingValueIndex ) ;
422- }
431+ // * Finished the first picker selection
432+ // * Some of start / end is not ready
433+ // Open miss value panel to force user input
434+ let nextOpenIndex : 0 | 1 = null ;
435+ if ( sourceIndex === 0 && ! mergedDisabled [ 1 ] ) {
436+ nextOpenIndex = 1 ;
437+ } else if ( sourceIndex === 1 && ! canStartValueTrigger ) {
438+ nextOpenIndex = 0 ;
439+ }
440+
441+ if (
442+ nextOpenIndex !== null &&
443+ nextOpenIndex !== mergedActivePickerIndex &&
444+ ! openRecordsRef . current [ nextOpenIndex ]
445+ ) {
446+ triggerOpen ( true , nextOpenIndex ) ;
423447
424448 // Delay to focus to avoid input blur trigger expired selectedValues
425449 setTimeout ( ( ) => {
426- const inputRef = [ startInputRef , endInputRef ] [ missingValueIndex ] ;
450+ const inputRef = [ startInputRef , endInputRef ] [ nextOpenIndex ] ;
427451 if ( inputRef . current ) {
428452 inputRef . current . focus ( ) ;
429453 }
430454 } , 0 ) ;
455+ } else {
456+ triggerOpen ( false , sourceIndex ) ;
431457 }
432- } ;
433-
434- triggerOpen = ( newOpen : boolean , index : 0 | 1 , preventChangeEvent : boolean = false ) => {
435- if ( newOpen ) {
436- setMergedActivePickerIndex ( index ) ;
437- triggerInnerOpen ( newOpen ) ;
438-
439- // Open to reset view date
440- if ( ! mergedOpen ) {
441- setViewDate ( null , index ) ;
442- }
443- } else if ( mergedActivePickerIndex === index ) {
444- triggerInnerOpen ( newOpen ) ;
445- if ( ! preventChangeEvent ) {
446- triggerChange ( selectedValue , { source : 'open' } ) ;
447- }
448- }
449- } ;
458+ }
450459
451460 const forwardKeyDown = ( e : React . KeyboardEvent < HTMLElement > ) => {
452461 if ( mergedOpen && operationRef . current && operationRef . current . onKeyDown ) {
@@ -493,12 +502,12 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
493502 }
494503 } ;
495504
496- const [ startText , triggerStartTextChange , resetStartText ] = useTextValueMapping < DateType > ( {
505+ const [ startText , triggerStartTextChange , resetStartText ] = useTextValueMapping ( {
497506 valueTexts : startValueTexts ,
498507 onTextChange : newText => onTextChange ( newText , 0 ) ,
499508 } ) ;
500509
501- const [ endText , triggerEndTextChange , resetEndText ] = useTextValueMapping < DateType > ( {
510+ const [ endText , triggerEndTextChange , resetEndText ] = useTextValueMapping ( {
502511 valueTexts : endValueTexts ,
503512 onTextChange : newText => onTextChange ( newText , 1 ) ,
504513 } ) ;
@@ -519,13 +528,23 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
519528 onFocus ( e ) ;
520529 }
521530 } ,
522- triggerOpen : ( newOpen : boolean ) => triggerOpen ( newOpen , index ) ,
531+ triggerOpen : ( newOpen : boolean ) => {
532+ // >>> triggerOpenOld(newOpen, index)
533+ triggerOpen ( newOpen , index ) ;
534+
535+ // Only blur will close open
536+ if ( ! newOpen && mergedActivePickerIndex === index ) {
537+ triggerChange ( selectedValue , index ) ;
538+ }
539+ } ,
523540 onSubmit : ( ) => {
524- triggerChange ( selectedValue ) ;
541+ // >>> triggerChangeOld(selectedValue);
542+ triggerChange ( selectedValue , index ) ;
525543 resetText ( ) ;
526544 } ,
527545 onCancel : ( ) => {
528- triggerOpen ( false , index , true ) ;
546+ // >>> triggerOpenOld(false, index, true);
547+ triggerOpen ( false , index ) ;
529548 setSelectedValue ( mergedValue ) ;
530549 resetText ( ) ;
531550 } ,
@@ -552,7 +571,7 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
552571 ? generateConfig . locale . format ( locale . locale , mergedValue [ 1 ] , 'YYYYMMDDHHmmss' )
553572 : '' ;
554573
555- React . useEffect ( ( ) => {
574+ useEffect ( ( ) => {
556575 if ( ! mergedOpen ) {
557576 setSelectedValue ( mergedValue ) ;
558577
@@ -570,7 +589,7 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
570589 } , [ mergedOpen , startValueTexts , endValueTexts ] ) ;
571590
572591 // Sync innerValue with control mode
573- React . useEffect ( ( ) => {
592+ useEffect ( ( ) => {
574593 setSelectedValue ( mergedValue ) ;
575594 } , [ startStr , endStr ] ) ;
576595
@@ -618,7 +637,8 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
618637 return {
619638 label,
620639 onClick : ( ) => {
621- triggerChange ( newValues ) ;
640+ // triggerChangeOld(newValues);
641+ triggerChange ( newValues , null ) ;
622642 } ,
623643 onMouseEnter : ( ) => {
624644 setRangeHoverValue ( newValues ) ;
@@ -754,7 +774,8 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
754774 rangeList,
755775 onOk : ( ) => {
756776 if ( getValue ( selectedValue , mergedActivePickerIndex ) ) {
757- triggerChange ( selectedValue ) ;
777+ // triggerChangeOld(selectedValue);
778+ triggerChange ( selectedValue , mergedActivePickerIndex ) ;
758779 if ( onOk ) {
759780 onOk ( selectedValue ) ;
760781 }
@@ -864,7 +885,8 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
864885 values = updateValues ( values , null , 1 ) ;
865886 }
866887
867- triggerChange ( values , { forceInput : false } ) ;
888+ // >>> triggerChangeOld(values, { forceInput: false });
889+ triggerChange ( values , null ) ;
868890 } }
869891 className = { `${ prefixCls } -clear` }
870892 >
@@ -895,7 +917,8 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
895917
896918 if ( type === 'submit' || ( type !== 'key' && ! needConfirmButton ) ) {
897919 // triggerChange will also update selected values
898- triggerChange ( values ) ;
920+ // triggerChangeOld(values);
921+ triggerChange ( values , mergedActivePickerIndex ) ;
899922 } else {
900923 setSelectedValue ( values ) ;
901924 }
0 commit comments