react-dates
Version:
A responsive and accessible date range picker component built with React
255 lines (225 loc) • 6.41 kB
JSX
import React from 'react';
import PropTypes from 'prop-types';
import { forbidExtraProps } from 'airbnb-prop-types';
import { css, withStyles, withStylesPropTypes } from 'react-with-styles';
import { SingleDatePickerInputPhrases } from '../defaultPhrases';
import getPhrasePropTypes from '../utils/getPhrasePropTypes';
import DateInput from './DateInput';
import IconPositionShape from '../shapes/IconPositionShape';
import CloseButton from './CloseButton';
import CalendarIcon from './CalendarIcon';
import openDirectionShape from '../shapes/OpenDirectionShape';
import { ICON_BEFORE_POSITION, ICON_AFTER_POSITION, OPEN_DOWN } from '../constants';
const propTypes = forbidExtraProps({
...withStylesPropTypes,
id: PropTypes.string.isRequired,
placeholder: PropTypes.string, // also used as label
displayValue: PropTypes.string,
screenReaderMessage: PropTypes.string,
focused: PropTypes.bool,
isFocused: PropTypes.bool, // describes actual DOM focus
disabled: PropTypes.bool,
required: PropTypes.bool,
readOnly: PropTypes.bool,
openDirection: openDirectionShape,
showCaret: PropTypes.bool,
showClearDate: PropTypes.bool,
customCloseIcon: PropTypes.node,
showDefaultInputIcon: PropTypes.bool,
inputIconPosition: IconPositionShape,
customInputIcon: PropTypes.node,
isRTL: PropTypes.bool,
onChange: PropTypes.func,
onClearDate: PropTypes.func,
onFocus: PropTypes.func,
onKeyDownShiftTab: PropTypes.func,
onKeyDownTab: PropTypes.func,
onKeyDownArrowDown: PropTypes.func,
onKeyDownQuestionMark: PropTypes.func,
// i18n
phrases: PropTypes.shape(getPhrasePropTypes(SingleDatePickerInputPhrases)),
});
const defaultProps = {
placeholder: 'Select Date',
displayValue: '',
screenReaderMessage: '',
focused: false,
isFocused: false,
disabled: false,
required: false,
readOnly: false,
openDirection: OPEN_DOWN,
showCaret: false,
showClearDate: false,
showDefaultInputIcon: false,
inputIconPosition: ICON_BEFORE_POSITION,
customCloseIcon: null,
customInputIcon: null,
isRTL: false,
onChange() {},
onClearDate() {},
onFocus() {},
onKeyDownShiftTab() {},
onKeyDownTab() {},
onKeyDownArrowDown() {},
onKeyDownQuestionMark() {},
// i18n
phrases: SingleDatePickerInputPhrases,
};
function SingleDatePickerInput({
id,
placeholder,
displayValue,
focused,
isFocused,
disabled,
required,
readOnly,
showCaret,
showClearDate,
showDefaultInputIcon,
inputIconPosition,
phrases,
onClearDate,
onChange,
onFocus,
onKeyDownShiftTab,
onKeyDownTab,
onKeyDownArrowDown,
onKeyDownQuestionMark,
screenReaderMessage,
customCloseIcon,
customInputIcon,
openDirection,
isRTL,
styles,
}) {
const calendarIcon = customInputIcon || (
<CalendarIcon {...css(styles.SingleDatePickerInput_calendarIcon_svg)} />
);
const closeIcon = customCloseIcon || (
<CloseButton {...css(styles.SingleDatePickerInput_clearDate_svg)} />
);
const screenReaderText = screenReaderMessage || phrases.keyboardNavigationInstructions;
const inputIcon = (showDefaultInputIcon || customInputIcon !== null) && (
<button
{...css(styles.SingleDatePickerInput_calendarIcon)}
type="button"
disabled={disabled}
aria-label={phrases.focusStartDate}
onClick={onFocus}
>
{calendarIcon}
</button>
);
return (
<div
{...css(
styles.SingleDatePickerInput,
disabled && styles.SingleDatePickerInput__disabled,
isRTL && styles.SingleDatePickerInput__rtl,
)}
>
{inputIconPosition === ICON_BEFORE_POSITION && inputIcon}
<DateInput
id={id}
placeholder={placeholder} // also used as label
displayValue={displayValue}
screenReaderMessage={screenReaderText}
focused={focused}
isFocused={isFocused}
disabled={disabled}
required={required}
readOnly={readOnly}
showCaret={showCaret}
onChange={onChange}
onFocus={onFocus}
onKeyDownShiftTab={onKeyDownShiftTab}
onKeyDownTab={onKeyDownTab}
onKeyDownArrowDown={onKeyDownArrowDown}
onKeyDownQuestionMark={onKeyDownQuestionMark}
openDirection={openDirection}
/>
{showClearDate && (
<button
{...css(
styles.SingleDatePickerInput_clearDate,
!displayValue && styles.SingleDatePickerInput_clearDate__hide,
)}
type="button"
aria-label={phrases.clearDate}
disabled={disabled}
onMouseEnter={this.onClearDateMouseEnter}
onMouseLeave={this.onClearDateMouseLeave}
onClick={onClearDate}
>
{closeIcon}
</button>
)}
{inputIconPosition === ICON_AFTER_POSITION && inputIcon}
</div>
);
}
SingleDatePickerInput.propTypes = propTypes;
SingleDatePickerInput.defaultProps = defaultProps;
export default withStyles(({ reactDates: { color } }) => ({
SingleDatePickerInput: {
backgroundColor: color.background,
border: `1px solid ${color.core.border}`,
},
SingleDatePickerInput__rtl: {
direction: 'rtl',
},
SingleDatePickerInput__disabled: {
backgroundColor: color.disabled,
},
SingleDatePickerInput_clearDate: {
background: 'none',
border: 0,
color: 'inherit',
font: 'inherit',
lineHeight: 'normal',
overflow: 'visible',
cursor: 'pointer',
display: 'inline-block',
verticalAlign: 'middle',
padding: 10,
margin: '0 10px 0 5px',
':focus': {
background: color.core.border,
borderRadius: '50%',
},
':hover': {
background: color.core.border,
borderRadius: '50%',
},
},
SingleDatePickerInput_clearDate__hide: {
visibility: 'hidden',
},
SingleDatePickerInput_clearDate_svg: {
fill: color.core.grayLight,
height: 12,
width: 15,
verticalAlign: 'middle',
},
SingleDatePickerInput_calendarIcon: {
background: 'none',
border: 0,
color: 'inherit',
font: 'inherit',
lineHeight: 'normal',
overflow: 'visible',
cursor: 'pointer',
display: 'inline-block',
verticalAlign: 'middle',
padding: 10,
margin: '0 5px 0 10px',
},
SingleDatePickerInput_calendarIcon_svg: {
fill: color.core.grayLight,
height: 15,
width: 14,
verticalAlign: 'middle',
},
}))(SingleDatePickerInput);