UNPKG

react-dates

Version:

A responsive and accessible date range picker component built with React

179 lines (162 loc) 5.18 kB
import React from 'react'; import PropTypes from 'prop-types'; import { forbidExtraProps } from 'airbnb-prop-types'; import cx from 'classnames'; import { DayPickerKeyboardShortcutsPhrases } from '../defaultPhrases'; import getPhrasePropTypes from '../utils/getPhrasePropTypes'; import CloseButton from '../svg/close.svg'; export const TOP_LEFT = 'top-left'; export const TOP_RIGHT = 'top-right'; export const BOTTOM_RIGHT = 'bottom-right'; const propTypes = forbidExtraProps({ block: PropTypes.bool, buttonLocation: PropTypes.oneOf([TOP_LEFT, TOP_RIGHT, BOTTOM_RIGHT]), showKeyboardShortcutsPanel: PropTypes.bool, openKeyboardShortcutsPanel: PropTypes.func, closeKeyboardShortcutsPanel: PropTypes.func, phrases: PropTypes.shape(getPhrasePropTypes(DayPickerKeyboardShortcutsPhrases)), }); const defaultProps = { block: false, buttonLocation: BOTTOM_RIGHT, showKeyboardShortcutsPanel: false, openKeyboardShortcutsPanel() {}, closeKeyboardShortcutsPanel() {}, phrases: DayPickerKeyboardShortcutsPhrases, }; export function KeyboardShortcutRow({ unicode, label, action }) { return ( <li className="KeyboardShortcutRow"> <div className="KeyboardShortcutRow__key-container" > <span className="KeyboardShortcutRow__key" role="img" aria-label={label} > {unicode} </span> </div> <div className="KeyboardShortcutRow__action"> {action} </div> </li> ); } KeyboardShortcutRow.propTypes = { unicode: PropTypes.string.isRequired, label: PropTypes.string.isRequired, action: PropTypes.string.isRequired, }; export default function DayPickerKeyboardShortcuts({ block, buttonLocation, showKeyboardShortcutsPanel, openKeyboardShortcutsPanel, closeKeyboardShortcutsPanel, phrases, }) { const keyboardShortcuts = [{ unicode: '↵', label: phrases.enterKey, action: phrases.selectFocusedDate, }, { unicode: '←/→', label: phrases.leftArrowRightArrow, action: phrases.moveFocusByOneDay, }, { unicode: '↑/↓', label: phrases.upArrowDownArrow, action: phrases.moveFocusByOneWeek, }, { unicode: 'PgUp/PgDn', label: phrases.pageUpPageDown, action: phrases.moveFocusByOneMonth, }, { unicode: 'Home/End', label: phrases.homeEnd, action: phrases.moveFocustoStartAndEndOfWeek, }, { unicode: 'Esc', label: phrases.escape, action: phrases.returnFocusToInput, }, { unicode: '?', label: phrases.questionMark, action: phrases.openThisPanel, }, ]; const toggleButtonText = showKeyboardShortcutsPanel ? phrases.hideKeyboardShortcutsPanel : phrases.showKeyboardShortcutsPanel; return ( <div> <button ref={(ref) => { this.showKeyboardShortcutsButton = ref; }} className={cx('DayPickerKeyboardShortcuts__show', { 'DayPickerKeyboardShortcuts__show--bottom-right': buttonLocation === BOTTOM_RIGHT, 'DayPickerKeyboardShortcuts__show--top-right': buttonLocation === TOP_RIGHT, 'DayPickerKeyboardShortcuts__show--top-left': buttonLocation === TOP_LEFT, })} type="button" aria-label={toggleButtonText} onClick={() => { // we want to return focus to this button after closing the keyboard shortcuts panel openKeyboardShortcutsPanel(() => { this.showKeyboardShortcutsButton.focus(); }); }} onMouseUp={(e) => { e.currentTarget.blur(); }} > <span className="DayPickerKeyboardShortcuts__show_span">?</span> </button> {showKeyboardShortcutsPanel && <div className={cx('DayPickerKeyboardShortcuts__panel', { 'DayPickerKeyboardShortcuts__panel--block': block, })} role="dialog" aria-labelledby="DayPickerKeyboardShortcuts__title" > <div id="DayPickerKeyboardShortcuts__title" className="DayPickerKeyboardShortcuts__title" > {phrases.keyboardShortcuts} </div> <button className="DayPickerKeyboardShortcuts__close" type="button" aria-label={phrases.hideKeyboardShortcutsPanel} onClick={closeKeyboardShortcutsPanel} onKeyDown={(e) => { // Because the close button is the only focusable element inside of the panel, this // amount to a very basic focus trap. The user can exit the panel by "pressing" the // close button or hitting escape if (e.key === 'Tab') { e.preventDefault(); } }} > <CloseButton /> </button> <ul className="DayPickerKeyboardShortcuts__list"> {keyboardShortcuts.map(({ unicode, label, action }) => ( <KeyboardShortcutRow key={label} unicode={unicode} label={label} action={action} /> ))} </ul> </div> } </div> ); } DayPickerKeyboardShortcuts.propTypes = propTypes; DayPickerKeyboardShortcuts.defaultProps = defaultProps;