UNPKG

baseui

Version:

A React Component library implementing the Base design language

391 lines (383 loc) • 16.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var React = _interopRequireWildcard(require("react")); var _styledComponents = require("./styled-components"); var _dateFnsAdapter = _interopRequireDefault(require("./utils/date-fns-adapter")); var _dateHelpers = _interopRequireDefault(require("./utils/date-helpers")); var _overrides = require("../helpers/overrides"); var _locale = require("../locale"); var _focusVisible = require("../utils/focusVisible"); var _constants = require("./constants"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /* Copyright (c) Uber Technologies, Inc. This source code is licensed under the MIT license found in the LICENSE file in the root directory of this source tree. */ class Day extends React.Component { constructor(props) { super(props); // @ts-ignore _defineProperty(this, "dayElm", void 0); _defineProperty(this, "state", { isHovered: false, isFocusVisible: false }); _defineProperty(this, "dateHelpers", void 0); _defineProperty(this, "getDateProp", () => { return this.props.date === undefined ? this.dateHelpers.date() : this.props.date; }); _defineProperty(this, "getMonthProp", () => { return this.props.month === undefined || this.props.month === null ? this.dateHelpers.getMonth(this.getDateProp()) : this.props.month; }); /** * Determines how the day value(s) should be updated when a new day is selected. * Note: time values are incorporated into new day/date values downstream in `Calendar`. * Note: Situations where Start Dates are after End Dates are handled downstream in `Datepicker`. * */ _defineProperty(this, "onSelect", selectedDate => { const { range, value } = this.props; let nextDate; if (Array.isArray(value) && range && this.props.hasLockedBehavior) { const currentDate = this.props.value; let nextStartDate = null; let nextEndDate = null; if (this.props.selectedInput === _constants.INPUT_ROLE.startDate) { // @ts-ignore nextStartDate = selectedDate; // @ts-ignore nextEndDate = Array.isArray(currentDate) && currentDate[1] ? currentDate[1] : null; } else if (this.props.selectedInput === _constants.INPUT_ROLE.endDate) { // @ts-ignore nextStartDate = Array.isArray(currentDate) && currentDate[0] ? currentDate[0] : null; // @ts-ignore nextEndDate = selectedDate; } nextDate = [nextStartDate]; if (nextEndDate) { nextDate.push(nextEndDate); } } else if (Array.isArray(value) && range && !this.props.hasLockedBehavior) { const [start, end] = value; // Starting a new range if (!start && !end || start && end) { nextDate = [selectedDate, null]; // EndDate needs a StartDate, SelectedDate comes before EndDate } else if (!start && end && this.dateHelpers.isAfter(end, selectedDate)) { nextDate = [selectedDate, end]; // EndDate needs a StartDate, but SelectedDate comes after EndDate } else if (!start && end && this.dateHelpers.isAfter(selectedDate, end)) { nextDate = [end, selectedDate]; // StartDate needs an EndDate, SelectedDate comes after StartDate } else if (start && !end && this.dateHelpers.isAfter(selectedDate, start)) { nextDate = [start, selectedDate]; } else { nextDate = [selectedDate, start]; } } else { nextDate = selectedDate; } this.props.onSelect({ date: nextDate }); }); _defineProperty(this, "onKeyDown", event => { const date = this.getDateProp(); const { highlighted, disabled } = this.props; if (event.key === 'Enter' && highlighted && !disabled) { event.preventDefault(); this.onSelect(date); } }); _defineProperty(this, "onClick", event => { const date = this.getDateProp(); const { disabled } = this.props; if (!disabled) { this.props.onClick({ event, date }); this.onSelect(date); } }); _defineProperty(this, "onFocus", event => { if ((0, _focusVisible.isFocusVisible)(event)) { this.setState({ isFocusVisible: true }); } this.props.onFocus({ event, date: this.getDateProp() }); }); _defineProperty(this, "onBlur", event => { if (this.state.isFocusVisible !== false) { this.setState({ isFocusVisible: false }); } this.props.onBlur({ event, date: this.getDateProp() }); }); _defineProperty(this, "onMouseOver", event => { this.setState({ isHovered: true }); this.props.onMouseOver({ event, date: this.getDateProp() }); }); _defineProperty(this, "onMouseLeave", event => { this.setState({ isHovered: false }); this.props.onMouseLeave({ event, date: this.getDateProp() }); }); _defineProperty(this, "isOutsideMonth", () => { const month = this.getMonthProp(); return month !== undefined && month !== this.dateHelpers.getMonth(this.getDateProp()); }); _defineProperty(this, "getOrderedDates", () => { const { highlightedDate, value } = this.props; if (!value || !Array.isArray(value) || !value[0] || !value[1] && !highlightedDate) { return []; } const firstValue = value[0]; const secondValue = value.length > 1 && value[1] ? value[1] : highlightedDate; if (!firstValue || !secondValue) { return []; } const firstDate = this.clampToDayStart(firstValue); const secondDate = this.clampToDayStart(secondValue); return this.dateHelpers.isAfter(firstDate, secondDate) ? [secondDate, firstDate] : [firstDate, secondDate]; }); _defineProperty(this, "isOutsideOfMonthButWithinRange", () => { const date = this.clampToDayStart(this.getDateProp()); const dates = this.getOrderedDates(); if (dates.length < 2 || this.dateHelpers.isSameDay(dates[0], dates[1])) { return false; } const day = this.dateHelpers.getDate(date); /** * Empty days (no number label) at the beginning/end of the month should be included * within the range if the last day of a month and the first day of the next month are * within the range. */ if (day > 15) { const firstDayOfNextMonth = this.clampToDayStart(this.dateHelpers.addDays(this.dateHelpers.getEndOfMonth(date), 1)); return this.dateHelpers.isOnOrBeforeDay(dates[0], this.dateHelpers.getEndOfMonth(date)) && this.dateHelpers.isOnOrAfterDay(dates[1], firstDayOfNextMonth); } else { const lastDayOfPreviousMonth = this.clampToDayStart(this.dateHelpers.subDays(this.dateHelpers.getStartOfMonth(date), 1)); return this.dateHelpers.isOnOrAfterDay(dates[1], this.dateHelpers.getStartOfMonth(date)) && this.dateHelpers.isOnOrBeforeDay(dates[0], lastDayOfPreviousMonth); } }); _defineProperty(this, "clampToDayStart", dt => { const { startOfDay } = this.dateHelpers; return startOfDay(dt); }); this.dateHelpers = new _dateHelpers.default(props.adapter); } componentDidMount() { if (this.dayElm && this.props.focusedCalendar) { if (this.props.highlighted || !this.props.highlightedDate && this.isSelected()) { this.dayElm.focus(); } } } // eslint-disable-next-line @typescript-eslint/no-unused-vars componentDidUpdate(prevProps) { if (this.dayElm && this.props.focusedCalendar) { if (this.props.highlighted || !this.props.highlightedDate && this.isSelected()) { this.dayElm.focus(); } } } isSelected() { const date = this.getDateProp(); const { value } = this.props; if (Array.isArray(value)) { return this.dateHelpers.isSameDay(date, value[0]) || this.dateHelpers.isSameDay(date, value[1]); } else { return this.dateHelpers.isSameDay(date, value); } } // calculated for range case only isPseudoSelected() { const date = this.getDateProp(); const { value } = this.props; if (Array.isArray(value)) { const [start, end] = value; if (!start && !end) { return false; } if (start && end) { return this.dateHelpers.isDayInRange(this.clampToDayStart(date), this.clampToDayStart(start), this.clampToDayStart(end)); } } } // calculated for range case only isPseudoHighlighted() { const date = this.getDateProp(); const { value, highlightedDate } = this.props; if (Array.isArray(value)) { const [start, end] = value; if (!start && !end) { return false; } if (highlightedDate && start && !end) { if (this.dateHelpers.isAfter(highlightedDate, start)) { return this.dateHelpers.isDayInRange(this.clampToDayStart(date), this.clampToDayStart(start), this.clampToDayStart(highlightedDate)); } else { return this.dateHelpers.isDayInRange(this.clampToDayStart(date), this.clampToDayStart(highlightedDate), this.clampToDayStart(start)); } } if (highlightedDate && !start && end) { if (this.dateHelpers.isAfter(highlightedDate, end)) { return this.dateHelpers.isDayInRange(this.clampToDayStart(date), this.clampToDayStart(end), this.clampToDayStart(highlightedDate)); } else { return this.dateHelpers.isDayInRange(this.clampToDayStart(date), this.clampToDayStart(highlightedDate), this.clampToDayStart(end)); } } } } getSharedProps() { const date = this.getDateProp(); const { value, highlightedDate, range, highlighted, peekNextMonth } = this.props; const $isHighlighted = highlighted; const $selected = this.isSelected(); const $hasRangeHighlighted = !!(Array.isArray(value) && range && highlightedDate && (value[0] && !value[1] && !this.dateHelpers.isSameDay(value[0], highlightedDate) || !value[0] && value[1] && !this.dateHelpers.isSameDay(value[1], highlightedDate))); const $outsideMonth = !peekNextMonth && this.isOutsideMonth(); const $outsideMonthWithinRange = !!(Array.isArray(value) && range && $outsideMonth && !peekNextMonth && this.isOutsideOfMonthButWithinRange()); return { $date: date, $density: this.props.density, $disabled: this.props.disabled, $endDate: Array.isArray(value) && !!(value[0] && value[1]) && range && $selected && this.dateHelpers.isSameDay(date, value[1]) || false, $hasDateLabel: !!this.props.dateLabel, $hasRangeHighlighted, $hasRangeOnRight: Array.isArray(value) && $hasRangeHighlighted && highlightedDate && (value[0] && this.dateHelpers.isAfter(highlightedDate, value[0]) || value[1] && this.dateHelpers.isAfter(highlightedDate, value[1])), $hasRangeSelected: Array.isArray(value) ? !!(value[0] && value[1]) : false, $highlightedDate: highlightedDate, $isHighlighted, $isHovered: this.state.isHovered, $isFocusVisible: this.state.isFocusVisible, $startOfMonth: this.dateHelpers.isStartOfMonth(date), $endOfMonth: this.dateHelpers.isEndOfMonth(date), $month: this.getMonthProp(), $outsideMonth, $outsideMonthWithinRange, $peekNextMonth: peekNextMonth, $pseudoHighlighted: range && !$isHighlighted && !$selected ? this.isPseudoHighlighted() : false, $pseudoSelected: range && !$selected ? this.isPseudoSelected() : false, $range: range, $selected, $startDate: Array.isArray(value) && value[0] && value[1] && range && $selected ? this.dateHelpers.isSameDay(date, value[0]) : false, $hasLockedBehavior: this.props.hasLockedBehavior, $selectedInput: this.props.selectedInput, $value: this.props.value }; } getAriaLabel(sharedProps, localeContext) { const date = this.getDateProp(); return `${sharedProps.$selected ? sharedProps.$range ? sharedProps.$endDate ? localeContext.datepicker.selectedEndDateLabel : localeContext.datepicker.selectedStartDateLabel : localeContext.datepicker.selectedLabel : sharedProps.$disabled ? localeContext.datepicker.dateNotAvailableLabel : localeContext.datepicker.chooseLabel} ${this.dateHelpers.format(date, 'fullOrdinalWeek', this.props.locale)}. ${!sharedProps.$disabled ? localeContext.datepicker.dateAvailableLabel : ''}`; } render() { const date = this.getDateProp(); const { peekNextMonth, overrides = {} } = this.props; const sharedProps = this.getSharedProps(); const [Day, dayProps] = (0, _overrides.getOverrides)(overrides.Day, _styledComponents.StyledDay); const [DayLabel, dayLabelProps] = (0, _overrides.getOverrides)(overrides.DayLabel, _styledComponents.StyledDayLabel); const dateLabel = this.props.dateLabel && this.props.dateLabel(date); return !peekNextMonth && sharedProps.$outsideMonth ? /*#__PURE__*/React.createElement(Day, _extends({ role: "gridcell" }, sharedProps, dayProps, { onFocus: this.onFocus, onBlur: this.onBlur })) : /*#__PURE__*/ // eslint-disable-next-line jsx-a11y/mouse-events-have-key-events React.createElement(_locale.LocaleContext.Consumer, null, locale => /*#__PURE__*/React.createElement(Day, _extends({ "aria-label": this.getAriaLabel(sharedProps, locale) // @ts-ignore , ref: dayElm => { this.dayElm = dayElm; }, role: "gridcell", "aria-roledescription": "button", tabIndex: this.props.highlighted || !this.props.highlightedDate && this.isSelected() ? 0 : -1 }, sharedProps, dayProps, { // Adding event handlers after customers overrides in order to // make sure the components functions as expected // We can extract the handlers from props overrides // and call it along with internal handlers by creating an inline handler onFocus: this.onFocus, onBlur: this.onBlur, onClick: this.onClick, onKeyDown: this.onKeyDown, onMouseOver: this.onMouseOver, onMouseLeave: this.onMouseLeave }), /*#__PURE__*/React.createElement("div", null, this.dateHelpers.getDate(date)), dateLabel ? /*#__PURE__*/React.createElement(DayLabel, _extends({}, sharedProps, dayLabelProps), dateLabel) : null)); } } exports.default = Day; _defineProperty(Day, "defaultProps", { disabled: false, highlighted: false, range: false, adapter: _dateFnsAdapter.default, onClick: () => {}, onSelect: () => {}, onFocus: () => {}, onBlur: () => {}, onMouseOver: () => {}, onMouseLeave: () => {}, overrides: {}, peekNextMonth: true, // @ts-ignore value: null });