Skip to content

Instantly share code, notes, and snippets.

@annjawn
Last active December 30, 2021 02:28
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save annjawn/66ba488a41883adcecb9b46c8853b5a3 to your computer and use it in GitHub Desktop.
Save annjawn/66ba488a41883adcecb9b46c8853b5a3 to your computer and use it in GitHub Desktop.
Keyboard and Performance friendly Ant Design Datepicker
import React, { Component } from "react";
import { Popover, Input, Calendar, Icon, Select, Button, Col, Row } from "antd";
import debounce from "lodash/debounce";
import moment from "moment";
import "antd/dist/antd.css";
class DatePicker extends Component {
static getDerivedStateFromProps(nextProps) {
// Should be a controlled component.
if ("value" in nextProps) {
return {
...(nextProps.value || {})
};
}
return null;
}
state = {
dateVal: "",
calVal: moment(),
popupVisible: false
};
dateChange = e => {
const date = e.target.value;
this.triggerChange({ date });
};
handleSelect = value => {
this.dateInput.focus();
const date = value.format(this.props.format);
this.triggerChange({ date });
};
triggerChange = changedValue => {
// Should provide an event to pass value to Form.
const { onChange, onBlur, dateChange, format } = this.props;
const debChange = debounce(changes => dateChange(changes.date), 300);
const calChange = debounce(dt => {
if (dt.length === format.length && moment(dt, format).isValid()) {
this.setState({ calVal: moment(dt) });
}
}, 300);
if (dateChange) {
debChange(changedValue);
}
if (onChange) {
calChange(changedValue.date);
this.setState({
dateVal: changedValue.date
});
}
if (onBlur) {
onBlur({
...changedValue
});
}
};
hidePopup = () => this.setState({ popupVisible: false });
visibilityChange = popupVisible => {
if (
document.activeElement === this.dateInput.input &&
!this.state.popupVisible
) {
this.setState({ popupVisible });
}
};
render() {
const { size, disabledDate, style, trigger } = this.props;
return (
<Popover
content={
<Calendar
fullscreen={false}
disabledDate={disabledDate}
value={this.state.calVal}
onSelect={value => {
this.handleSelect(value);
}}
headerRender={({ value, type, onChange, onTypeChange }) => {
const start = 0;
const end = 12;
const monthOptions = [];
const current = value.clone();
const localeData = value.localeData();
const months = [];
for (let i = 0; i < 12; i++) {
current.month(i);
months.push(localeData.months(current));
}
for (let index = start; index < end; index++) {
monthOptions.push(
<Select.Option className="month-item" key={`${index}`}>
{months[index]}
</Select.Option>
);
}
const month = value.month();
const year = value.year();
const options = [];
for (let i = year - 10; i < year + 10; i += 1) {
options.push(
<Select.Option key={i} value={i} className="year-item">
{i}
</Select.Option>
);
}
return (
<div style={{ padding: 10 }}>
<Row type="flex" justify="space-between">
<Col>
<Select
size="small"
dropdownMatchSelectWidth={false}
className="my-year-select"
onChange={newYear => {
const now = value.clone().year(newYear);
onChange(now);
}}
value={String(year)}
>
{options}
</Select>
</Col>
<Col>
<Select
size="small"
dropdownMatchSelectWidth={false}
value={String(month)}
onChange={selectedMonth => {
const newValue = value.clone();
newValue.month(parseInt(selectedMonth, 10));
onChange(newValue);
}}
>
{monthOptions}
</Select>
</Col>
<Col>
<Button
type="link"
size={size}
icon="close-circle"
onClick={this.hidePopup}
style={{ height: "16px", width: "16px" }}
/>
</Col>
</Row>
</div>
);
}}
/>
}
visible={this.state.popupVisible}
onVisibleChange={this.visibilityChange}
placement="bottom"
trigger={trigger}
>
<Input
placeholder={this.props.placeholder}
size={size}
value={this.state.dateVal}
onChange={this.dateChange}
onKeyDown={e => {
//hide popup on tab or esc
if (e.keyCode === 9 || e.keyCode === 27) {
this.setState({ popupVisible: false });
}
}}
allowClear
suffix={<Icon type="calendar" style={{ opacity: "0.5" }} />}
style={style}
ref={input => {
this.dateInput = input;
}}
/>
</Popover>
);
}
}
export default DatePicker;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment