import _extends from "@babel/runtime/helpers/esm/extends"; import _assertThisInitialized from "@babel/runtime/helpers/esm/assertThisInitialized"; import _inheritsLoose from "@babel/runtime/helpers/esm/inheritsLoose"; import _defineProperty from "@babel/runtime/helpers/esm/defineProperty"; import shallowEqual from "enzyme-shallow-equal"; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } import React from 'react'; import PropTypes from 'prop-types'; import { forbidExtraProps } from 'airbnb-prop-types'; import { css, withStyles, withStylesPropTypes } from 'react-with-styles'; import { DayPickerKeyboardShortcutsPhrases } from '../defaultPhrases'; import getPhrasePropTypes from '../utils/getPhrasePropTypes'; import KeyboardShortcutRow from './KeyboardShortcutRow'; import CloseButton from './CloseButton'; export var TOP_LEFT = 'top-left'; export var TOP_RIGHT = 'top-right'; export var BOTTOM_RIGHT = 'bottom-right'; var propTypes = process.env.NODE_ENV !== "production" ? forbidExtraProps(_objectSpread({}, withStylesPropTypes, { block: PropTypes.bool, // TODO: rename button location to be direction-agnostic buttonLocation: PropTypes.oneOf([TOP_LEFT, TOP_RIGHT, BOTTOM_RIGHT]), showKeyboardShortcutsPanel: PropTypes.bool, openKeyboardShortcutsPanel: PropTypes.func, closeKeyboardShortcutsPanel: PropTypes.func, phrases: PropTypes.shape(getPhrasePropTypes(DayPickerKeyboardShortcutsPhrases)), renderKeyboardShortcutsButton: PropTypes.func, renderKeyboardShortcutsPanel: PropTypes.func })) : {}; var defaultProps = { block: false, buttonLocation: BOTTOM_RIGHT, showKeyboardShortcutsPanel: false, openKeyboardShortcutsPanel: function openKeyboardShortcutsPanel() {}, closeKeyboardShortcutsPanel: function closeKeyboardShortcutsPanel() {}, phrases: DayPickerKeyboardShortcutsPhrases, renderKeyboardShortcutsButton: undefined, renderKeyboardShortcutsPanel: undefined }; function getKeyboardShortcuts(phrases) { return [{ 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 }]; } var DayPickerKeyboardShortcuts = /*#__PURE__*/ function (_ref) { _inheritsLoose(DayPickerKeyboardShortcuts, _ref); var _proto = DayPickerKeyboardShortcuts.prototype; _proto[!React.PureComponent && "shouldComponentUpdate"] = function (nextProps, nextState) { return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState); }; function DayPickerKeyboardShortcuts() { var _this; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _ref.call.apply(_ref, [this].concat(args)) || this; var phrases = _this.props.phrases; _this.keyboardShortcuts = getKeyboardShortcuts(phrases); _this.onShowKeyboardShortcutsButtonClick = _this.onShowKeyboardShortcutsButtonClick.bind(_assertThisInitialized(_this)); _this.setShowKeyboardShortcutsButtonRef = _this.setShowKeyboardShortcutsButtonRef.bind(_assertThisInitialized(_this)); _this.setHideKeyboardShortcutsButtonRef = _this.setHideKeyboardShortcutsButtonRef.bind(_assertThisInitialized(_this)); _this.handleFocus = _this.handleFocus.bind(_assertThisInitialized(_this)); _this.onKeyDown = _this.onKeyDown.bind(_assertThisInitialized(_this)); return _this; } _proto.componentWillReceiveProps = function componentWillReceiveProps(nextProps) { var phrases = this.props.phrases; if (nextProps.phrases !== phrases) { this.keyboardShortcuts = getKeyboardShortcuts(nextProps.phrases); } }; _proto.componentDidUpdate = function componentDidUpdate() { this.handleFocus(); }; _proto.onKeyDown = function onKeyDown(e) { e.stopPropagation(); var closeKeyboardShortcutsPanel = this.props.closeKeyboardShortcutsPanel; // Because the close button is the only focusable element inside of the panel, this // amounts to a very basic focus trap. The user can exit the panel by "pressing" the // close button or hitting escape switch (e.key) { case 'Escape': closeKeyboardShortcutsPanel(); break; // do nothing - this allows the up and down arrows continue their // default behavior of scrolling the content of the Keyboard Shortcuts Panel // which is needed when only a single month is shown for instance. case 'ArrowUp': case 'ArrowDown': break; // completely block the rest of the keys that have functionality outside of this panel case 'Tab': case 'Home': case 'End': case 'PageUp': case 'PageDown': case 'ArrowLeft': case 'ArrowRight': e.preventDefault(); break; default: break; } }; _proto.onShowKeyboardShortcutsButtonClick = function onShowKeyboardShortcutsButtonClick() { var _this2 = this; var openKeyboardShortcutsPanel = this.props.openKeyboardShortcutsPanel; // we want to return focus to this button after closing the keyboard shortcuts panel openKeyboardShortcutsPanel(function () { _this2.showKeyboardShortcutsButton.focus(); }); }; _proto.setShowKeyboardShortcutsButtonRef = function setShowKeyboardShortcutsButtonRef(ref) { this.showKeyboardShortcutsButton = ref; }; _proto.setHideKeyboardShortcutsButtonRef = function setHideKeyboardShortcutsButtonRef(ref) { this.hideKeyboardShortcutsButton = ref; }; _proto.handleFocus = function handleFocus() { if (this.hideKeyboardShortcutsButton) { // automatically move focus into the dialog by moving // to the only interactive element, the hide button this.hideKeyboardShortcutsButton.focus(); } }; _proto.render = function render() { var _this$props = this.props, block = _this$props.block, buttonLocation = _this$props.buttonLocation, showKeyboardShortcutsPanel = _this$props.showKeyboardShortcutsPanel, closeKeyboardShortcutsPanel = _this$props.closeKeyboardShortcutsPanel, styles = _this$props.styles, phrases = _this$props.phrases, renderKeyboardShortcutsButton = _this$props.renderKeyboardShortcutsButton, renderKeyboardShortcutsPanel = _this$props.renderKeyboardShortcutsPanel; var toggleButtonText = showKeyboardShortcutsPanel ? phrases.hideKeyboardShortcutsPanel : phrases.showKeyboardShortcutsPanel; var bottomRight = buttonLocation === BOTTOM_RIGHT; var topRight = buttonLocation === TOP_RIGHT; var topLeft = buttonLocation === TOP_LEFT; return React.createElement("div", null, renderKeyboardShortcutsButton && renderKeyboardShortcutsButton({ // passing in context-specific props ref: this.setShowKeyboardShortcutsButtonRef, onClick: this.onShowKeyboardShortcutsButtonClick, ariaLabel: toggleButtonText }), !renderKeyboardShortcutsButton && React.createElement("button", _extends({ ref: this.setShowKeyboardShortcutsButtonRef }, css(styles.DayPickerKeyboardShortcuts_buttonReset, styles.DayPickerKeyboardShortcuts_show, bottomRight && styles.DayPickerKeyboardShortcuts_show__bottomRight, topRight && styles.DayPickerKeyboardShortcuts_show__topRight, topLeft && styles.DayPickerKeyboardShortcuts_show__topLeft), { type: "button", "aria-label": toggleButtonText, onClick: this.onShowKeyboardShortcutsButtonClick, onMouseUp: function onMouseUp(e) { e.currentTarget.blur(); } }), React.createElement("span", css(styles.DayPickerKeyboardShortcuts_showSpan, bottomRight && styles.DayPickerKeyboardShortcuts_showSpan__bottomRight, topRight && styles.DayPickerKeyboardShortcuts_showSpan__topRight, topLeft && styles.DayPickerKeyboardShortcuts_showSpan__topLeft), "?")), showKeyboardShortcutsPanel && (renderKeyboardShortcutsPanel ? renderKeyboardShortcutsPanel({ closeButtonAriaLabel: phrases.hideKeyboardShortcutsPanel, keyboardShortcuts: this.keyboardShortcuts, onCloseButtonClick: closeKeyboardShortcutsPanel, onKeyDown: this.onKeyDown, title: phrases.keyboardShortcuts }) : React.createElement("div", _extends({}, css(styles.DayPickerKeyboardShortcuts_panel), { role: "dialog", "aria-labelledby": "DayPickerKeyboardShortcuts_title", "aria-describedby": "DayPickerKeyboardShortcuts_description" }), React.createElement("div", _extends({}, css(styles.DayPickerKeyboardShortcuts_title), { id: "DayPickerKeyboardShortcuts_title" }), phrases.keyboardShortcuts), React.createElement("button", _extends({ ref: this.setHideKeyboardShortcutsButtonRef }, css(styles.DayPickerKeyboardShortcuts_buttonReset, styles.DayPickerKeyboardShortcuts_close), { type: "button", tabIndex: "0", "aria-label": phrases.hideKeyboardShortcutsPanel, onClick: closeKeyboardShortcutsPanel, onKeyDown: this.onKeyDown }), React.createElement(CloseButton, css(styles.DayPickerKeyboardShortcuts_closeSvg))), React.createElement("ul", _extends({}, css(styles.DayPickerKeyboardShortcuts_list), { id: "DayPickerKeyboardShortcuts_description" }), this.keyboardShortcuts.map(function (_ref2) { var unicode = _ref2.unicode, label = _ref2.label, action = _ref2.action; return React.createElement(KeyboardShortcutRow, { key: label, unicode: unicode, label: label, action: action, block: block }); }))))); }; return DayPickerKeyboardShortcuts; }(React.PureComponent || React.Component); DayPickerKeyboardShortcuts.propTypes = process.env.NODE_ENV !== "production" ? propTypes : {}; DayPickerKeyboardShortcuts.defaultProps = defaultProps; export default withStyles(function (_ref3) { var _ref3$reactDates = _ref3.reactDates, color = _ref3$reactDates.color, font = _ref3$reactDates.font, zIndex = _ref3$reactDates.zIndex; return { DayPickerKeyboardShortcuts_buttonReset: { background: 'none', border: 0, borderRadius: 0, color: 'inherit', font: 'inherit', lineHeight: 'normal', overflow: 'visible', padding: 0, cursor: 'pointer', fontSize: font.size, ':active': { outline: 'none' } }, DayPickerKeyboardShortcuts_show: { width: 33, height: 26, position: 'absolute', zIndex: zIndex + 2, '::before': { content: '""', display: 'block', position: 'absolute' } }, DayPickerKeyboardShortcuts_show__bottomRight: { bottom: 0, right: 0, '::before': { borderTop: '26px solid transparent', borderRight: "33px solid ".concat(color.core.primary), bottom: 0, right: 0 }, ':hover::before': { borderRight: "33px solid ".concat(color.core.primary_dark) } }, DayPickerKeyboardShortcuts_show__topRight: { top: 0, right: 0, '::before': { borderBottom: '26px solid transparent', borderRight: "33px solid ".concat(color.core.primary), top: 0, right: 0 }, ':hover::before': { borderRight: "33px solid ".concat(color.core.primary_dark) } }, DayPickerKeyboardShortcuts_show__topLeft: { top: 0, left: 0, '::before': { borderBottom: '26px solid transparent', borderLeft: "33px solid ".concat(color.core.primary), top: 0, left: 0 }, ':hover::before': { borderLeft: "33px solid ".concat(color.core.primary_dark) } }, DayPickerKeyboardShortcuts_showSpan: { color: color.core.white, position: 'absolute' }, DayPickerKeyboardShortcuts_showSpan__bottomRight: { bottom: 0, right: 5 }, DayPickerKeyboardShortcuts_showSpan__topRight: { top: 1, right: 5 }, DayPickerKeyboardShortcuts_showSpan__topLeft: { top: 1, left: 5 }, DayPickerKeyboardShortcuts_panel: { overflow: 'auto', background: color.background, border: "1px solid ".concat(color.core.border), borderRadius: 2, position: 'absolute', top: 0, bottom: 0, right: 0, left: 0, zIndex: zIndex + 2, padding: 22, margin: 33, textAlign: 'left' // TODO: investigate use of text-align throughout the library }, DayPickerKeyboardShortcuts_title: { fontSize: 16, fontWeight: 'bold', margin: 0 }, DayPickerKeyboardShortcuts_list: { listStyle: 'none', padding: 0, fontSize: font.size }, DayPickerKeyboardShortcuts_close: { position: 'absolute', right: 22, top: 22, zIndex: zIndex + 2, ':active': { outline: 'none' } }, DayPickerKeyboardShortcuts_closeSvg: { height: 15, width: 15, fill: color.core.grayLighter, ':hover': { fill: color.core.grayLight }, ':focus': { fill: color.core.grayLight } } }; }, { pureComponent: typeof React.PureComponent !== 'undefined' })(DayPickerKeyboardShortcuts);