Skip to content

Commit d7f63e5

Browse files
committed
feat: RangePicker support focus
1 parent 2045b0b commit d7f63e5

File tree

3 files changed

+108
-13
lines changed

3 files changed

+108
-13
lines changed

src/RangePicker.tsx

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ export interface RangePickerSharedProps<DateType> {
5252
value: RangeValue<DateType>,
5353
formatString: [string, string],
5454
) => void;
55+
onFocus?: React.FocusEventHandler<HTMLInputElement>;
56+
onBlur?: React.FocusEventHandler<HTMLInputElement>;
5557
}
5658

5759
type OmitPickerProps<Props> = Omit<
@@ -93,7 +95,11 @@ interface MergedRangePickerProps<DateType>
9395
picker?: PickerMode;
9496
}
9597

96-
function RangePicker<DateType>(props: RangePickerProps<DateType>) {
98+
function InternalRangePicker<DateType>(
99+
props: RangePickerProps<DateType> & {
100+
pickerRef: React.Ref<Picker>;
101+
},
102+
) {
97103
const {
98104
prefixCls = 'rc-picker',
99105
className,
@@ -103,6 +109,7 @@ function RangePicker<DateType>(props: RangePickerProps<DateType>) {
103109
defaultPickerValue,
104110
separator = '~',
105111
picker,
112+
pickerRef,
106113
locale,
107114
generateConfig,
108115
placeholder,
@@ -116,7 +123,11 @@ function RangePicker<DateType>(props: RangePickerProps<DateType>) {
116123
disabled,
117124
onChange,
118125
onCalendarChange,
119-
} = props as MergedRangePickerProps<DateType>;
126+
onFocus,
127+
onBlur,
128+
} = props as MergedRangePickerProps<DateType> & {
129+
pickerRef: React.Ref<Picker>;
130+
};
120131

121132
const formatList = toArray(
122133
getDefaultFormat(format, picker, showTime, use12Hours),
@@ -188,10 +199,12 @@ function RangePicker<DateType>(props: RangePickerProps<DateType>) {
188199
};
189200

190201
// ============================= Change =============================
191-
const formatDate = (date: NullableDateType<DateType>) =>
192-
(date
193-
? generateConfig.locale.format(locale.locale, date, formatList[0])
194-
: '');
202+
const formatDate = (date: NullableDateType<DateType>) => {
203+
if (date) {
204+
return generateConfig.locale.format(locale.locale, date, formatList[0]);
205+
}
206+
return '';
207+
};
195208

196209
const onInternalChange = (
197210
values: NullableDateType<DateType>[],
@@ -306,6 +319,7 @@ function RangePicker<DateType>(props: RangePickerProps<DateType>) {
306319
>
307320
<Picker<DateType>
308321
{...pickerProps}
322+
ref={pickerRef}
309323
prefixCls={prefixCls}
310324
value={value1}
311325
placeholder={placeholder && placeholder[0]}
@@ -317,6 +331,8 @@ function RangePicker<DateType>(props: RangePickerProps<DateType>) {
317331
onInternalChange([date, value2], true);
318332
}}
319333
onSelect={onStartSelect}
334+
onFocus={onFocus}
335+
onBlur={onBlur}
320336
/>
321337
{separator}
322338
<Picker<DateType>
@@ -332,10 +348,40 @@ function RangePicker<DateType>(props: RangePickerProps<DateType>) {
332348
onInternalChange([value1, date], false);
333349
}}
334350
onSelect={onEndSelect}
351+
onFocus={onFocus}
352+
onBlur={onBlur}
335353
/>
336354
</div>
337355
</RangeContext.Provider>
338356
);
339357
}
340358

359+
// Wrap with class component to enable pass generic with instance method
360+
class RangePicker<DateType> extends React.Component<
361+
RangePickerProps<DateType>
362+
> {
363+
pickerRef = React.createRef<HTMLInputElement>();
364+
365+
focus = () => {
366+
if (this.pickerRef.current) {
367+
this.pickerRef.current.focus();
368+
}
369+
};
370+
371+
blur = () => {
372+
if (this.pickerRef.current) {
373+
this.pickerRef.current.blur();
374+
}
375+
};
376+
377+
render() {
378+
return (
379+
<InternalRangePicker<DateType>
380+
{...this.props}
381+
pickerRef={this.pickerRef}
382+
/>
383+
);
384+
}
385+
}
386+
341387
export default RangePicker;

tests/range.spec.tsx

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react';
22
import MockDate from 'mockdate';
3+
import { spyElementPrototypes } from 'rc-util/lib/test/domHook';
34
import { Moment } from 'moment';
45
import {
56
mount,
@@ -385,4 +386,45 @@ describe('Range', () => {
385386
expect(disabledTime.mock.calls[0][1]).toEqual('end');
386387
wrapper.closePicker(1);
387388
});
389+
390+
describe('focus test', () => {
391+
let domMock: ReturnType<typeof spyElementPrototypes>;
392+
let focused = false;
393+
let blurred = false;
394+
395+
beforeAll(() => {
396+
domMock = spyElementPrototypes(HTMLElement, {
397+
focus: () => {
398+
focused = true;
399+
},
400+
blur: () => {
401+
blurred = true;
402+
},
403+
});
404+
});
405+
406+
beforeEach(() => {
407+
focused = false;
408+
blurred = false;
409+
});
410+
411+
afterAll(() => {
412+
domMock.mockRestore();
413+
});
414+
415+
it('function call', () => {
416+
const ref = React.createRef<MomentRangePicker>();
417+
mount(
418+
<div>
419+
<MomentRangePicker ref={ref} />
420+
</div>,
421+
);
422+
423+
ref.current!.rangePickerRef.current!.focus();
424+
expect(focused).toBeTruthy();
425+
426+
ref.current!.rangePickerRef.current!.blur();
427+
expect(blurred).toBeTruthy();
428+
});
429+
});
388430
});

tests/util/commonUtil.tsx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,17 @@ export type MomentRangePickerProps =
114114
| InjectDefaultProps<RangePickerDateProps<Moment>>
115115
| InjectDefaultProps<RangePickerTimeProps<Moment>>;
116116

117-
export const MomentRangePicker = (props: MomentRangePickerProps) => (
118-
<RangePicker<Moment>
119-
generateConfig={momentGenerateConfig}
120-
locale={enUS}
121-
{...props}
122-
/>
123-
);
117+
export class MomentRangePicker extends React.Component<MomentRangePickerProps> {
118+
rangePickerRef = React.createRef<RangePicker<Moment>>();
119+
120+
render() {
121+
return (
122+
<RangePicker<Moment>
123+
generateConfig={momentGenerateConfig}
124+
locale={enUS}
125+
ref={this.rangePickerRef}
126+
{...this.props}
127+
/>
128+
);
129+
}
130+
}

0 commit comments

Comments
 (0)