Skip to content

Commit 19a599b

Browse files
authored
feat: Picker disabledTime support info.form (#803)
* chore: init * chore: base interface * chore: do it * test: add test case * chore: fix lint
1 parent dafb237 commit 19a599b

File tree

10 files changed

+128
-25
lines changed

10 files changed

+128
-25
lines changed

docs/examples/debug.tsx

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,56 @@ export default () => {
4646
return (
4747
<div>
4848
<input defaultValue="2000-01-01" />
49-
<RangePicker
49+
{/* <RangePicker
5050
{...sharedLocale}
5151
style={{ width: 400 }}
5252
onChange={(val) => console.error('>>>>>>>', val)}
53+
/> */}
54+
<RangePicker
55+
{...sharedLocale}
56+
style={{ width: 400 }}
57+
showTime
58+
// disabledDate={(_, info) => {
59+
// console.log('Date:', info);
60+
// return false;
61+
// }}
62+
disabledTime={(date, range, info) => {
63+
// console.log(`Time-${range}`, range, info);
64+
const { from } = info;
65+
66+
if (from) {
67+
console.log(
68+
`Time-${range}`,
69+
from.format('YYYY-MM-DD HH:mm:ss'),
70+
date.format('YYYY-MM-DD HH:mm:ss'),
71+
);
72+
}
73+
74+
if (from && from.isSame(date, 'day')) {
75+
return {
76+
disabledHours: () => [from.hour()],
77+
disabledMinutes: () => [0, 1, 2, 3],
78+
disabledSeconds: () => [0, 1, 2, 3],
79+
};
80+
}
81+
return {};
82+
}}
5383
/>
54-
{/* <RangePicker {...sharedLocale} style={{ width: 400 }} showTime showMinute={false} /> */}
55-
{/* <SinglePicker {...dateFnsSharedLocale} style={{ width: 400 }} multiple placeholder="good" /> */}
56-
<SinglePicker
84+
{/* <SinglePicker
85+
{...dateFnsSharedLocale}
86+
style={{ width: 400 }}
87+
showTime
88+
disabledTime={(...args) => {
89+
console.log('Time Single:', ...args);
90+
return {};
91+
}}
92+
/> */}
93+
{/* <SinglePicker
5794
{...sharedLocale}
5895
style={{ width: 400 }}
5996
minDate={dayjs()}
6097
onChange={(val) => console.error('>>>>>>>', val)}
61-
/>
98+
/> */}
6299
</div>
63100
);
64101
};

src/PickerInput/Popup/Footer.tsx

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,9 @@ import classNames from 'classnames';
22
import * as React from 'react';
33
import type { GenerateConfig } from '../../generate';
44
import useTimeInfo from '../../hooks/useTimeInfo';
5-
import type {
6-
DisabledDate,
7-
InternalMode,
8-
PanelMode,
9-
RangeTimeProps,
10-
SharedPickerProps,
11-
} from '../../interface';
5+
import type { DisabledDate, InternalMode, PanelMode, SharedPickerProps } from '../../interface';
126
import PickerContext from '../context';
7+
import type { PopupShowTimeConfig } from '.';
138

149
export interface FooterProps<DateType extends object = any> {
1510
mode: PanelMode;
@@ -18,7 +13,7 @@ export interface FooterProps<DateType extends object = any> {
1813
showNow: boolean;
1914
generateConfig: GenerateConfig<DateType>;
2015
disabledDate: DisabledDate<DateType>;
21-
showTime?: Omit<RangeTimeProps<DateType>, 'defaultValue' | 'defaultOpenValue'>;
16+
showTime?: PopupShowTimeConfig<DateType>;
2217

2318
// Invalid
2419
/** From Footer component used only. Check if can OK button click */

src/PickerInput/Popup/index.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
11
import classNames from 'classnames';
22
import ResizeObserver, { type ResizeObserverProps } from 'rc-resize-observer';
33
import * as React from 'react';
4-
import type { SharedPickerProps, ValueDate } from '../../interface';
4+
import type {
5+
RangeTimeProps,
6+
SharedPickerProps,
7+
SharedTimeProps,
8+
ValueDate,
9+
} from '../../interface';
510
import { toArray } from '../../utils/miscUtil';
611
import PickerContext from '../context';
712
import Footer, { type FooterProps } from './Footer';
813
import PopupPanel, { type PopupPanelProps } from './PopupPanel';
914
import PresetPanel from './PresetPanel';
1015

16+
export type PopupShowTimeConfig<DateType extends object = any> = Omit<
17+
RangeTimeProps<DateType>,
18+
'defaultValue' | 'defaultOpenValue' | 'disabledTime'
19+
> &
20+
Pick<SharedTimeProps<DateType>, 'disabledTime'>;
21+
1122
export interface PopupProps<DateType extends object = any, PresetValue = DateType>
1223
extends Pick<React.InputHTMLAttributes<HTMLDivElement>, 'onFocus' | 'onBlur'>,
1324
FooterProps<DateType>,

src/PickerInput/RangePicker.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import type {
2020
import type { PickerPanelProps } from '../PickerPanel';
2121
import PickerTrigger from '../PickerTrigger';
2222
import { pickTriggerProps } from '../PickerTrigger/util';
23-
import { fillIndex, toArray } from '../utils/miscUtil';
23+
import { fillIndex, getFromDate, toArray } from '../utils/miscUtil';
2424
import PickerContext from './context';
2525
import useCellRender from './hooks/useCellRender';
2626
import useFieldsInvalidate from './hooks/useFieldsInvalidate';
@@ -33,7 +33,7 @@ import useRangeDisabledDate from './hooks/useRangeDisabledDate';
3333
import useRangePickerValue from './hooks/useRangePickerValue';
3434
import useRangeValue, { useInnerValue } from './hooks/useRangeValue';
3535
import useShowNow from './hooks/useShowNow';
36-
import Popup from './Popup';
36+
import Popup, { PopupShowTimeConfig } from './Popup';
3737
import RangeSelector, { type SelectorIdType } from './Selector/RangeSelector';
3838

3939
function separateConfig<T>(config: T | [T, T] | null | undefined, defaultConfig: T): [T, T] {
@@ -278,7 +278,10 @@ function RangePicker<DateType extends object = any>(
278278
};
279279

280280
// ======================= ShowTime =======================
281-
const mergedShowTime = React.useMemo(() => {
281+
/** Used for Popup panel */
282+
const mergedShowTime = React.useMemo<
283+
PopupShowTimeConfig<DateType> & Pick<RangeTimeProps<DateType>, 'defaultOpenValue'>
284+
>(() => {
282285
if (!showTime) {
283286
return null;
284287
}
@@ -288,12 +291,15 @@ function RangePicker<DateType extends object = any>(
288291
const proxyDisabledTime = disabledTime
289292
? (date: DateType) => {
290293
const range = getActiveRange(activeIndex);
291-
return disabledTime(date, range);
294+
const fromDate = getFromDate(calendarValue, activeIndexList, activeIndex);
295+
return disabledTime(date, range, {
296+
from: fromDate,
297+
});
292298
}
293299
: undefined;
294300

295301
return { ...showTime, disabledTime: proxyDisabledTime };
296-
}, [showTime, activeIndex]);
302+
}, [showTime, activeIndex, calendarValue, activeIndexList]);
297303

298304
// ========================= Mode =========================
299305
const [modes, setModes] = useMergedState<[PanelMode, PanelMode]>([picker, picker], {
@@ -542,6 +548,7 @@ function RangePicker<DateType extends object = any>(
542548
'style',
543549
'className',
544550
'onPanelChange',
551+
'disabledTime',
545552
]);
546553
return restProps;
547554
}, [filledProps]);

src/PickerInput/hooks/useInvalidate.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,11 @@ export default function useInvalidate<DateType extends object = any>(
3535
}
3636

3737
if ((picker === 'date' || picker === 'time') && showTime) {
38+
const range = info && info.activeIndex === 1 ? 'end' : 'start';
3839
const { disabledHours, disabledMinutes, disabledSeconds, disabledMilliseconds } =
39-
showTime.disabledTime?.(date, info && info.activeIndex === 1 ? 'end' : 'start') || {};
40+
showTime.disabledTime?.(date, range, {
41+
from: outsideInfo.from,
42+
}) || {};
4043

4144
const {
4245
disabledHours: legacyDisabledHours,

src/PickerInput/hooks/useRangeDisabledDate.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { GenerateConfig } from '../../generate';
22
import { isSame } from '../../utils/dateUtil';
33
import type { DisabledDate, Locale } from '../../interface';
44
import type { RangeValueType } from '../RangePicker';
5+
import { getFromDate } from '../../utils/miscUtil';
56

67
/**
78
* RangePicker need additional logic to handle the `disabled` case. e.g.
@@ -16,14 +17,13 @@ export default function useRangeDisabledDate<DateType extends object = any>(
1617
disabledDate?: DisabledDate<DateType>,
1718
) {
1819
const activeIndex = activeIndexList[activeIndexList.length - 1];
19-
const firstValuedIndex = activeIndexList.find((index) => values[index]);
2020

2121
const rangeDisabledDate: DisabledDate<DateType> = (date, info) => {
2222
const [start, end] = values;
2323

2424
const mergedInfo = {
2525
...info,
26-
from: activeIndex !== firstValuedIndex ? values[firstValuedIndex] : undefined,
26+
from: getFromDate(values, activeIndexList),
2727
};
2828

2929
// ============================ Disabled ============================

src/PickerTrigger/util.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { SharedPickerProps } from '../interface';
22
import { pickProps } from '../utils/miscUtil';
33

4-
export function pickTriggerProps(props: SharedPickerProps) {
4+
export function pickTriggerProps(props: Omit<SharedPickerProps, 'showTime'>) {
55
return pickProps(props, [
66
'placement',
77
'builtinPlacements',

src/interface.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,19 +176,25 @@ export interface SharedTimeProps<DateType extends object = any> {
176176
disabledSeconds?: DisabledTimes['disabledSeconds'];
177177

178178
/** Only work in picker is `time` */
179-
disabledTime?: (date: DateType, range?: 'start' | 'end') => DisabledTimes;
179+
disabledTime?: (date: DateType) => DisabledTimes;
180180

181181
/** Only work in picker is `time` */
182182
changeOnScroll?: boolean;
183183
}
184184

185185
export type RangeTimeProps<DateType extends object = any> = Omit<
186186
SharedTimeProps<DateType>,
187-
'defaultValue' | 'defaultOpenValue'
187+
'defaultValue' | 'defaultOpenValue' | 'disabledTime'
188188
> & {
189189
/** @deprecated Use `defaultOpenValue` instead. */
190190
defaultValue?: DateType[];
191191
defaultOpenValue?: DateType[];
192+
193+
disabledTime?: (
194+
date: DateType,
195+
range: 'start' | 'end',
196+
info: { from?: DateType },
197+
) => DisabledTimes;
192198
};
193199

194200
// ======================= Components =======================

src/utils/miscUtil.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,15 @@ export function getRowFormat(
6969
return locale.fieldDateFormat;
7070
}
7171
}
72+
73+
export function getFromDate<DateType>(
74+
calendarValues: DateType[],
75+
activeIndexList: number[],
76+
activeIndex?: number,
77+
) {
78+
const mergedActiveIndex =
79+
activeIndex !== undefined ? activeIndex : activeIndexList[activeIndexList.length - 1];
80+
const firstValuedIndex = activeIndexList.find((index) => calendarValues[index]);
81+
82+
return mergedActiveIndex !== firstValuedIndex ? calendarValues[firstValuedIndex] : undefined;
83+
}

tests/new-range.spec.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,4 +1294,36 @@ describe('NewPicker.Range', () => {
12941294
'1990-09-24 02:00:00',
12951295
]);
12961296
});
1297+
1298+
it('disabledTime support `from` info', () => {
1299+
const disabledTime = jest.fn(() => ({}));
1300+
1301+
const { container } = render(
1302+
<DayRangePicker
1303+
showTime={{
1304+
disabledTime,
1305+
}}
1306+
/>,
1307+
);
1308+
1309+
openPicker(container);
1310+
expect(disabledTime).toHaveBeenCalledWith(expect.anything(), 'start', {});
1311+
disabledTime.mockReset();
1312+
1313+
// Select
1314+
selectCell(5);
1315+
fireEvent.doubleClick(findCell(5));
1316+
1317+
let existed = false;
1318+
for (let i = 0; i < disabledTime.mock.calls.length; i += 1) {
1319+
const args: any[] = disabledTime.mock.calls[i];
1320+
if (
1321+
args[1] === 'end' &&
1322+
args[2]?.from?.format('YYYY-MM-DD HH:mm:ss') === '1990-09-05 00:00:00'
1323+
) {
1324+
existed = true;
1325+
}
1326+
}
1327+
expect(existed).toBeTruthy();
1328+
});
12971329
});

0 commit comments

Comments
 (0)