Skip to content

Commit 0180c7f

Browse files
authored
chore: Adjust close logic (#90)
* clean up * both open * add test case * lock eslint * more test case
1 parent 8cf9ffe commit 0180c7f

File tree

4 files changed

+165
-87
lines changed

4 files changed

+165
-87
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
"enzyme": "^3.0.0",
6363
"enzyme-adapter-react-16": "^1.0.1",
6464
"enzyme-to-json": "^3.4.0",
65-
"eslint": "^7.0.0",
65+
"eslint": "~7.2.0",
6666
"eslint-plugin-eslint-comments": "^3.1.2",
6767
"eslint-plugin-jest": "^23.0.5",
6868
"eslint-plugin-react-hooks": "^4.0.2",

src/RangePicker.tsx

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
206206

207207
const needConfirmButton: boolean = (picker === 'date' && !!showTime) || picker === 'time';
208208

209+
// We record opened status here in case repeat open with picker
210+
const openRecordsRef = useRef<Record<number, boolean>>({});
211+
209212
const containerRef = useRef<HTMLDivElement>(null);
210213
const panelDivRef = useRef<HTMLDivElement>(null);
211214
const startInputDivRef = useRef<HTMLDivElement>(null);
@@ -301,14 +304,18 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
301304
};
302305

303306
// ========================= Disable Date ==========================
304-
const [disabledStartDate, disabledEndDate] = useRangeDisabled({
305-
picker,
306-
selectedValue,
307-
locale,
308-
disabled: mergedDisabled,
309-
disabledDate,
310-
generateConfig,
311-
});
307+
const [disabledStartDate, disabledEndDate] = useRangeDisabled(
308+
{
309+
picker,
310+
selectedValue,
311+
locale,
312+
disabled: mergedDisabled,
313+
disabledDate,
314+
generateConfig,
315+
},
316+
openRecordsRef.current[1],
317+
openRecordsRef.current[0],
318+
);
312319

313320
// ============================= Open ==============================
314321
const [mergedOpen, triggerInnerOpen] = useMergedState(false, {
@@ -339,14 +346,11 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
339346
}, [mergedOpen]);
340347

341348
// ============================ Trigger ============================
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>>({});
349+
const triggerRef = React.useRef<any>();
347350

348351
function triggerOpen(newOpen: boolean, index: 0 | 1) {
349352
if (newOpen) {
353+
clearTimeout(triggerRef.current);
350354
openRecordsRef.current[index] = true;
351355

352356
setMergedActivePickerIndex(index);
@@ -357,8 +361,16 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
357361
setViewDate(null, index);
358362
}
359363
} else if (mergedActivePickerIndex === index) {
360-
openRecordsRef.current = {};
361364
triggerInnerOpen(newOpen);
365+
366+
// Clean up async
367+
// This makes ref not quick refresh in case user open another input with blur trigger
368+
const openRecords = openRecordsRef.current;
369+
triggerRef.current = setTimeout(() => {
370+
if (openRecords === openRecordsRef.current) {
371+
openRecordsRef.current = {};
372+
}
373+
});
362374
}
363375
}
364376

@@ -428,20 +440,19 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
428440

429441
// >>>>> Open picker when
430442

431-
// * Finished the first picker selection
432-
// * Some of start / end is not ready
433-
// Open miss value panel to force user input
443+
// Always open another picker if possible
434444
let nextOpenIndex: 0 | 1 = null;
435445
if (sourceIndex === 0 && !mergedDisabled[1]) {
436446
nextOpenIndex = 1;
437-
} else if (sourceIndex === 1 && !canStartValueTrigger) {
447+
} else if (sourceIndex === 1 && !mergedDisabled[0]) {
438448
nextOpenIndex = 0;
439449
}
440450

441451
if (
442452
nextOpenIndex !== null &&
443453
nextOpenIndex !== mergedActivePickerIndex &&
444-
!openRecordsRef.current[nextOpenIndex]
454+
!openRecordsRef.current[nextOpenIndex] &&
455+
getValue(values, sourceIndex)
445456
) {
446457
triggerOpen(true, nextOpenIndex);
447458

@@ -529,21 +540,18 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
529540
}
530541
},
531542
triggerOpen: (newOpen: boolean) => {
532-
// >>> triggerOpenOld(newOpen, index)
533543
triggerOpen(newOpen, index);
534544

535545
// Only blur will close open
536-
if (!newOpen && mergedActivePickerIndex === index) {
546+
if (!newOpen && mergedOpen !== newOpen && mergedActivePickerIndex === index) {
537547
triggerChange(selectedValue, index);
538548
}
539549
},
540550
onSubmit: () => {
541-
// >>> triggerChangeOld(selectedValue);
542551
triggerChange(selectedValue, index);
543552
resetText();
544553
},
545554
onCancel: () => {
546-
// >>> triggerOpenOld(false, index, true);
547555
triggerOpen(false, index);
548556
setSelectedValue(mergedValue);
549557
resetText();
@@ -885,7 +893,6 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
885893
values = updateValues(values, null, 1);
886894
}
887895

888-
// >>> triggerChangeOld(values, { forceInput: false });
889896
triggerChange(values, null);
890897
}}
891898
className={`${prefixCls}-clear`}

src/hooks/useRangeDisabled.ts

Lines changed: 78 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,75 +4,112 @@ import { getValue } from '../utils/miscUtil';
44
import { GenerateConfig } from '../generate';
55
import { isSameDate, getQuarter } from '../utils/dateUtil';
66

7-
export default function useRangeDisabled<DateType>({
8-
picker,
9-
locale,
10-
selectedValue,
11-
disabledDate,
12-
disabled,
13-
generateConfig,
14-
}: {
15-
picker: PickerMode;
16-
selectedValue: RangeValue<DateType>;
17-
disabledDate?: (date: DateType) => boolean;
18-
disabled: [boolean, boolean];
19-
locale: Locale;
20-
generateConfig: GenerateConfig<DateType>;
21-
}) {
7+
export default function useRangeDisabled<DateType>(
8+
{
9+
picker,
10+
locale,
11+
selectedValue,
12+
disabledDate,
13+
disabled,
14+
generateConfig,
15+
}: {
16+
picker: PickerMode;
17+
selectedValue: RangeValue<DateType>;
18+
disabledDate?: (date: DateType) => boolean;
19+
disabled: [boolean, boolean];
20+
locale: Locale;
21+
generateConfig: GenerateConfig<DateType>;
22+
},
23+
disabledStart: boolean,
24+
disabledEnd: boolean,
25+
) {
2226
const startDate = getValue(selectedValue, 0);
2327
const endDate = getValue(selectedValue, 1);
2428

29+
function weekNumber(date: DateType) {
30+
const year = generateConfig.getYear(date);
31+
const week = generateConfig.locale.getWeek(locale.locale, date);
32+
return year * 100 + week;
33+
}
34+
35+
function monthNumber(date: DateType) {
36+
const year = generateConfig.getYear(date);
37+
const month = generateConfig.getMonth(date);
38+
return year * 100 + month;
39+
}
40+
41+
function quarterNumber(date: DateType) {
42+
const year = generateConfig.getYear(date);
43+
const quarter = getQuarter(generateConfig, date);
44+
return year * 10 + quarter;
45+
}
46+
2547
const disabledStartDate = React.useCallback(
2648
(date: DateType) => {
2749
if (disabledDate && disabledDate(date)) {
2850
return true;
2951
}
3052

53+
// Disabled range
3154
if (disabled[1] && endDate) {
3255
return !isSameDate(generateConfig, date, endDate) && generateConfig.isAfter(date, endDate);
3356
}
3457

58+
// Disabled part
59+
if (disabledStart && endDate) {
60+
switch (picker) {
61+
case 'quarter':
62+
return quarterNumber(date) > quarterNumber(endDate);
63+
case 'month':
64+
return monthNumber(date) > monthNumber(endDate);
65+
case 'week':
66+
return weekNumber(date) > weekNumber(endDate);
67+
default:
68+
return (
69+
!isSameDate(generateConfig, date, endDate) && generateConfig.isAfter(date, endDate)
70+
);
71+
}
72+
}
73+
3574
return false;
3675
},
37-
[disabledDate, disabled[1], endDate],
76+
[disabledDate, disabled[1], endDate, disabledStart],
3877
);
3978

40-
const disableEndDate = React.useCallback(
79+
const disabledEndDate = React.useCallback(
4180
(date: DateType) => {
4281
if (disabledDate && disabledDate(date)) {
4382
return true;
4483
}
4584

46-
if (startDate) {
47-
if (picker === 'week') {
48-
const startYear = generateConfig.getYear(startDate);
49-
const dateYear = generateConfig.getYear(date);
50-
const startWeek = generateConfig.locale.getWeek(locale.locale, startDate);
51-
const dateWeek = generateConfig.locale.getWeek(locale.locale, date);
52-
const startVal = startYear * 100 + startWeek;
53-
const dateVal = dateYear * 100 + dateWeek;
54-
return dateVal < startVal;
55-
}
56-
57-
if (picker === 'quarter') {
58-
const startYear = generateConfig.getYear(startDate);
59-
const dateYear = generateConfig.getYear(date);
60-
const startQuarter = getQuarter(generateConfig, startDate);
61-
const dateQuarter = getQuarter(generateConfig, date);
62-
const startVal = startYear * 10 + startQuarter;
63-
const dateVal = dateYear * 10 + dateQuarter;
64-
return dateVal < startVal;
65-
}
66-
85+
// Disabled range
86+
if (disabled[0] && startDate) {
6787
return (
68-
!isSameDate(generateConfig, date, startDate) && generateConfig.isAfter(startDate, date)
88+
!isSameDate(generateConfig, date, endDate) && generateConfig.isAfter(startDate, date)
6989
);
7090
}
7191

92+
// Disabled part
93+
if (disabledEnd && startDate) {
94+
switch (picker) {
95+
case 'quarter':
96+
return quarterNumber(date) < quarterNumber(startDate);
97+
case 'month':
98+
return monthNumber(date) < monthNumber(startDate);
99+
case 'week':
100+
return weekNumber(date) < weekNumber(startDate);
101+
default:
102+
return (
103+
!isSameDate(generateConfig, date, startDate) &&
104+
generateConfig.isAfter(startDate, date)
105+
);
106+
}
107+
}
108+
72109
return false;
73110
},
74-
[disabledDate, startDate, picker],
111+
[disabledDate, disabled[0], startDate, disabledEnd],
75112
);
76113

77-
return [disabledStartDate, disableEndDate];
114+
return [disabledStartDate, disabledEndDate];
78115
}

0 commit comments

Comments
 (0)