baseui
Version:
A React Component library implementing the Base design language
391 lines (383 loc) • 16.9 kB
JavaScript
"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
});