Skip to content

Commit bbdf1c0

Browse files
committed
feat: Close first Picker will open last Picker
1 parent 033b691 commit bbdf1c0

File tree

3 files changed

+101
-15
lines changed

3 files changed

+101
-15
lines changed

examples/range.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ export default () => {
3939
onCalendarChange,
4040
};
4141

42+
const rangePickerRef = React.useRef<RangePicker<Moment>>(null);
43+
4244
return (
4345
<div>
4446
<h1>
@@ -49,7 +51,20 @@ export default () => {
4951
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
5052
<div style={{ margin: '0 8px' }}>
5153
<h3>Basic</h3>
52-
<RangePicker<Moment> {...sharedProps} locale={zhCN} allowClear />
54+
<RangePicker<Moment>
55+
{...sharedProps}
56+
locale={zhCN}
57+
allowClear
58+
ref={rangePickerRef}
59+
/>
60+
<button
61+
type="button"
62+
onClick={() => {
63+
rangePickerRef.current!.focus();
64+
}}
65+
>
66+
Focus!
67+
</button>
5368
</div>
5469
<div style={{ margin: '0 8px' }}>
5570
<h3>Basic</h3>

src/Picker.tsx

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ import {
3131
addGlobalMouseDownEvent,
3232
} from './utils/uiUtil';
3333

34+
export interface PickerRefConfig {
35+
focus: () => void;
36+
blur: () => void;
37+
open: () => void;
38+
}
39+
3440
export interface PickerSharedProps<DateType> extends React.AriaAttributes {
3541
dropdownClassName?: string;
3642
dropdownAlign?: AlignType;
@@ -70,7 +76,7 @@ export interface PickerSharedProps<DateType> extends React.AriaAttributes {
7076

7177
// Internal
7278
/** @private Internal usage, do not use in production mode!!! */
73-
inputRef?: React.Ref<HTMLInputElement>;
79+
pickerRef?: React.MutableRefObject<PickerRefConfig>;
7480

7581
// WAI-ARIA
7682
role?: string;
@@ -134,7 +140,7 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
134140
disabledDate,
135141
placeholder,
136142
getPopupContainer,
137-
inputRef,
143+
pickerRef,
138144
onChange,
139145
onOpenChange,
140146
onFocus,
@@ -147,6 +153,8 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
147153
onClick,
148154
} = props as MergedPickerProps<DateType>;
149155

156+
const inputRef = React.useRef<HTMLInputElement>(null);
157+
150158
// ============================= State =============================
151159
const formatList = toArray(
152160
getDefaultFormat(format, picker, showTime, use12Hours),
@@ -416,6 +424,25 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
416424
}),
417425
);
418426

427+
// ============================ Private ============================
428+
if (pickerRef) {
429+
pickerRef.current = {
430+
focus: () => {
431+
if (inputRef.current) {
432+
inputRef.current.focus();
433+
}
434+
},
435+
blur: () => {
436+
if (inputRef.current) {
437+
inputRef.current.blur();
438+
}
439+
},
440+
open: () => {
441+
triggerOpen(true);
442+
},
443+
};
444+
}
445+
419446
// ============================= Panel =============================
420447
const panelProps = {
421448
// Remove `picker` & `format` here since TimePicker is little different with other panel
@@ -519,22 +546,33 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
519546

520547
// Wrap with class component to enable pass generic with instance method
521548
class Picker<DateType> extends React.Component<PickerProps<DateType>> {
522-
inputRef = React.createRef<HTMLInputElement>();
549+
pickerRef = React.createRef<PickerRefConfig>();
523550

524551
focus = () => {
525-
if (this.inputRef.current) {
526-
this.inputRef.current.focus();
552+
if (this.pickerRef.current) {
553+
this.pickerRef.current.focus();
527554
}
528555
};
529556

530557
blur = () => {
531-
if (this.inputRef.current) {
532-
this.inputRef.current.blur();
558+
if (this.pickerRef.current) {
559+
this.pickerRef.current.blur();
560+
}
561+
};
562+
563+
open = () => {
564+
if (this.pickerRef.current) {
565+
this.pickerRef.current.open();
533566
}
534567
};
535568

536569
render() {
537-
return <InnerPicker<DateType> {...this.props} inputRef={this.inputRef} />;
570+
return (
571+
<InnerPicker<DateType>
572+
{...this.props}
573+
pickerRef={this.pickerRef as React.MutableRefObject<PickerRefConfig>}
574+
/>
575+
);
538576
}
539577
}
540578

src/RangePicker.tsx

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Picker, {
1010
PickerBaseProps,
1111
PickerDateProps,
1212
PickerTimeProps,
13+
PickerRefConfig,
1314
} from './Picker';
1415
import {
1516
NullableDateType,
@@ -121,7 +122,7 @@ interface MergedRangePickerProps<DateType>
121122

122123
function InternalRangePicker<DateType>(
123124
props: RangePickerProps<DateType> & {
124-
pickerRef: React.Ref<Picker<DateType>>;
125+
pickerRef: React.Ref<PickerRefConfig>;
125126
},
126127
) {
127128
const {
@@ -152,7 +153,7 @@ function InternalRangePicker<DateType>(
152153
onFocus,
153154
onBlur,
154155
} = props as MergedRangePickerProps<DateType> & {
155-
pickerRef: React.Ref<Picker<DateType>>;
156+
pickerRef: React.MutableRefObject<PickerRefConfig>;
156157
};
157158

158159
const formatList = toArray(
@@ -262,8 +263,38 @@ function InternalRangePicker<DateType>(
262263
}
263264
};
264265

265-
// ============================== Mode ==============================
266+
// ============================== Open ==============================
267+
const startPickerRef = React.useRef<Picker<DateType>>(null);
268+
const endPickerRef = React.useRef<Picker<DateType>>(null);
269+
const lastOpenIdRef = React.useRef<number>();
270+
271+
const onStartOpenChange = (open: boolean) => {
272+
if (!open && innerValue && innerValue[0]) {
273+
lastOpenIdRef.current = window.setTimeout(() => {
274+
if (endPickerRef.current) {
275+
endPickerRef.current!.focus();
276+
endPickerRef.current!.open();
277+
}
278+
}, 100);
279+
}
280+
281+
if (props.onOpenChange) {
282+
props.onOpenChange(open);
283+
}
284+
};
266285

286+
React.useEffect(
287+
() => () => {
288+
window.clearTimeout(lastOpenIdRef.current);
289+
},
290+
[],
291+
);
292+
293+
if (pickerRef) {
294+
pickerRef.current = startPickerRef.current as any;
295+
}
296+
297+
// ============================== Mode ==============================
267298
/**
268299
* [Legacy] handle internal `onPanelChange`
269300
*/
@@ -407,7 +438,7 @@ function InternalRangePicker<DateType>(
407438
>
408439
<Picker<DateType>
409440
{...pickerProps}
410-
ref={pickerRef}
441+
ref={startPickerRef}
411442
prefixCls={prefixCls}
412443
value={value1}
413444
placeholder={placeholder && placeholder[0]}
@@ -423,10 +454,12 @@ function InternalRangePicker<DateType>(
423454
onFocus={onFocus}
424455
onBlur={onBlur}
425456
onPanelChange={onStartPanelChange}
457+
onOpenChange={onStartOpenChange}
426458
/>
427459
{separator}
428460
<Picker<DateType>
429461
{...pickerProps}
462+
ref={endPickerRef}
430463
prefixCls={prefixCls}
431464
value={value2}
432465
placeholder={placeholder && placeholder[1]}
@@ -452,7 +485,7 @@ function InternalRangePicker<DateType>(
452485
class RangePicker<DateType> extends React.Component<
453486
RangePickerProps<DateType>
454487
> {
455-
pickerRef = React.createRef<Picker<DateType>>();
488+
pickerRef = React.createRef<PickerRefConfig>();
456489

457490
focus = () => {
458491
if (this.pickerRef.current) {
@@ -470,7 +503,7 @@ class RangePicker<DateType> extends React.Component<
470503
return (
471504
<InternalRangePicker<DateType>
472505
{...this.props}
473-
pickerRef={this.pickerRef}
506+
pickerRef={this.pickerRef as React.MutableRefObject<PickerRefConfig>}
474507
/>
475508
);
476509
}

0 commit comments

Comments
 (0)