UNPKG

react-dates-rtl

Version:

Based on react-dates by airbnb [with RTL support]

200 lines (173 loc) 5.17 kB
import React from 'react'; import PropTypes from 'prop-types'; import { forbidExtraProps } from 'airbnb-prop-types'; import cx from 'classnames'; import throttle from 'lodash.throttle'; import isTouchDevice from '../utils/isTouchDevice'; const propTypes = forbidExtraProps({ id: PropTypes.string.isRequired, placeholder: PropTypes.string, // also used as label displayValue: PropTypes.string, inputValue: PropTypes.string, screenReaderMessage: PropTypes.string, focused: PropTypes.bool, disabled: PropTypes.bool, required: PropTypes.bool, showCaret: PropTypes.bool, onChange: PropTypes.func, onFocus: PropTypes.func, onKeyDownShiftTab: PropTypes.func, onKeyDownTab: PropTypes.func, onKeyDownArrowDown: PropTypes.func, onKeyDownQuestionMark: PropTypes.func, // accessibility isFocused: PropTypes.bool, // describes actual DOM focus }); const defaultProps = { placeholder: 'Select Date', displayValue: '', inputValue: '', screenReaderMessage: '', focused: false, disabled: false, required: false, showCaret: false, onChange() {}, onFocus() {}, onKeyDownShiftTab() {}, onKeyDownTab() {}, onKeyDownArrowDown() {}, onKeyDownQuestionMark() {}, // accessibility isFocused: false, }; export default class DateInput extends React.Component { constructor(props) { super(props); this.state = { dateString: '', isTouchDevice: false, }; this.onChange = this.onChange.bind(this); this.onKeyDown = this.onKeyDown.bind(this); } componentDidMount() { this.setState({ isTouchDevice: isTouchDevice() }); } componentWillReceiveProps(nextProps) { if (!this.props.displayValue && nextProps.displayValue) { this.setState({ dateString: '', }); } } componentDidUpdate(prevProps) { const { focused, isFocused } = this.props; if (prevProps.focused === focused && prevProps.isFocused === isFocused) return; if (focused && isFocused) { this.inputRef.focus(); this.inputRef.select(); } else { this.inputRef.blur(); } } onChange(e) { const { onChange, onKeyDownQuestionMark } = this.props; const dateString = e.target.value; // In Safari, onKeyDown does not consistently fire ahead of onChange. As a result, we need to // special case the `?` key so that it always triggers the appropriate callback, instead of // modifying the input value if (dateString[dateString.length - 1] === '?') { onKeyDownQuestionMark(e); } else { this.setState({ dateString }); onChange(dateString); } } onKeyDown(e) { e.stopPropagation(); const { onKeyDownShiftTab, onKeyDownTab, onKeyDownArrowDown, onKeyDownQuestionMark, } = this.props; const { key } = e; if (key === 'Tab') { if (e.shiftKey) { onKeyDownShiftTab(e); } else { onKeyDownTab(e); } } else if (key === 'ArrowDown') { onKeyDownArrowDown(e); } else if (key === '?') { e.preventDefault(); onKeyDownQuestionMark(e); } } render() { const { dateString, isTouchDevice: isTouch, } = this.state; const { id, placeholder, displayValue, inputValue, screenReaderMessage, focused, showCaret, onFocus, disabled, required, } = this.props; const displayText = displayValue || inputValue || dateString || placeholder || ''; const value = inputValue || displayValue || dateString || ''; const screenReaderMessageId = `DateInput__screen-reader-message-${id}`; return ( <div className={cx('DateInput', { 'DateInput--with-caret': showCaret && focused, 'DateInput--disabled': disabled, })} > <input aria-label={placeholder} className="DateInput__input needsclick" type="text" id={id} name={id} ref={(ref) => { this.inputRef = ref; }} value={value} onChange={this.onChange} onKeyDown={throttle(this.onKeyDown, 300)} onFocus={onFocus} placeholder={placeholder} autoComplete="off" disabled={disabled} readOnly={isTouch} required={required} aria-describedby={screenReaderMessage && screenReaderMessageId} /> {screenReaderMessage && ( <p id={screenReaderMessageId} className="screen-reader-only"> {screenReaderMessage} </p> )} <div className={cx('DateInput__display-text', { 'DateInput__display-text--has-input': !!value, 'DateInput__display-text--focused': focused, 'DateInput__display-text--disabled': disabled, })} > {displayText} </div> </div> ); } } DateInput.propTypes = propTypes; DateInput.defaultProps = defaultProps;