@progress/kendo-react-dateinputs
Version:
React DateInput is a perfect input component for handling quick and efficient date values. KendoReact Date Inputs package
465 lines (464 loc) • 19.1 kB
JavaScript
/**
* @license
*-------------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the package root for more information
*-------------------------------------------------------------------------------------------
*/
import * as d from "react";
import s from "prop-types";
import { provideIntlService as G, provideLocalizationService as X, registerForIntl as q, registerForLocalization as J } from "@progress/kendo-react-intl";
import { Keys as O, validatePackage as Q, getLicenseMessage as Z, classNames as ee, WatermarkOverlay as te, createPropsContext as se, withIdHOC as ie, withPropsContext as ae } from "@progress/kendo-react-common";
import { isEqualDate as P, addDays as M, cloneDate as m, getDate as g, firstDayOfMonth as ne, lastDayOfMonth as oe } from "@progress/kendo-date-math";
import { Button as L } from "@progress/kendo-react-buttons";
import { chevronRightIcon as N, chevronLeftIcon as B } from "@progress/kendo-svg-icons";
import { Action as k } from "../models/NavigationAction.mjs";
import { CalendarViewEnum as A } from "../models/CalendarViewEnum.mjs";
import { EMPTY_SELECTIONRANGE as j } from "../models/SelectionRange.mjs";
import { Header as re } from "./Header.mjs";
import { dateInRange as x, getToday as F, viewInRange as _, nullable as D, MIN_DATE as le, MAX_DATE as he, isInRange as T } from "../../utils.mjs";
import { prevView as K, messages as Y, nextView as W } from "../../messages/index.mjs";
import { BusViewService as ce } from "../services/BusViewService.mjs";
import { NavigationService as de } from "../services/NavigationService.mjs";
import { HorizontalViewList as E } from "./HorizontalViewList.mjs";
import { TodayCommand as ue } from "./TodayCommand.mjs";
import { packageMetadata as z } from "../../package-metadata.mjs";
const S = (l = v.defaultProps.min, i = v.defaultProps.max, a) => a instanceof Date && !Array.isArray(a) && T(g(a), l, i) ? g(a) : null, U = (l = v.defaultProps.min, i = v.defaultProps.max, a) => Array.isArray(a) ? a.filter((c) => T(c, l, i)).map((c) => g(c)) : null, $ = (l) => typeof l == "object" && !(l instanceof Date) && l !== null && !Array.isArray(l) ? l : j, H = (l, i, a) => l || i && i[0] || a && a.start, pe = (l, i) => l.start === null && i === null ? "start" : l.end === null ? "end" : "start", u = class u extends d.Component {
constructor(i) {
super(i), this.dates = [], this.selectedDate = null, this.selectedMultiple = null, this.selectedRange = j, this._focusedDate = /* @__PURE__ */ new Date(), this.cellUID = this.props.id + "-cell-uid", this.activeRangeEnd = "start", this._element = null, this.intl = null, this.localization = null, this.service = null, this.calendarViewList = null, this.isActive = !1, this.calculateFocusFromValue = !0, this.showLicenseWatermark = !1, this.focus = () => {
this._element && this._element.focus();
}, this.clampRange = (e) => ({ start: e, end: null }), this.rangeWithFocused = (e, t) => ({
start: e.start,
end: e.end === null && e.start !== null && this.isActive ? t : e.end
}), this.generateRange = (e, t) => {
const { end: r, start: o } = t, h = t.start !== null && e.getTime() <= t.start.getTime();
return !this.props.allowReverse && h ? { start: e, end: this.selectedRange.start } : this.activeRange !== "end" ? { start: e, end: r } : { start: o || this.selectedDate, end: e };
}, this.canNavigate = (e) => {
if (!this.service)
return !1;
const t = this.service.move(this.focusedDate, e);
return this.min <= t && t <= this.max || this.service.isInSameView(t, this.min) || this.service.isInSameView(t, this.max);
}, this.navigate = (e, t) => {
this.calculateFocusFromValue = !1;
const r = this.move(e, t);
this.setState({ navigateDate: r, focusedDate: r });
}, this.move = (e, t) => this.clampDate(this.service.move(t, e)), this.clampDate = (e) => x(e, this.min, this.max), this.shouldAutoCorrect = (e, t) => {
const { end: r, start: o } = t;
return this.activeRange !== "end" ? r !== null && e > r : o !== null && e < o;
}, this.handleCellEnter = (e) => {
this.props.mode === "range" && (this.calculateFocusFromValue = !1, this.setState({
focusedDate: e
}));
}, this.handleMouseDown = (e) => {
e.preventDefault();
}, this.handleClick = (e) => {
this._element && this._element.focus({ preventScroll: !0 });
}, this.handleFocus = (e) => {
if (this.isActive = !0, !this.calendarViewList)
return;
this.calendarViewList.focusActiveDate();
const { onFocus: t } = this.props;
t && t.call(void 0, e);
}, this.handleBlur = (e) => {
if (this.isActive = !1, !this.calendarViewList)
return;
this.calendarViewList.blurActiveDate();
const { onBlur: t } = this.props;
t && t.call(void 0, e);
}, this.handleTodayClick = (e) => {
this.todayIsInRange && this.handleDateChange(e);
}, this.handlePrevButtonClick = () => {
const e = k.PrevView;
if (this.state.activeView > 0 && this.focusedDate.getFullYear() > this.dates[0].getFullYear())
this.navigate(e, this.move(e, this.focusedDate));
else {
const t = this.isInMonth(this.focusedDate, this.dates[1]) ? this.move(e, this.focusedDate) : this.focusedDate;
this.navigate(e, t);
}
}, this.handleNextButtonClick = () => {
this.navigate(k.NextView, this.focusedDate);
}, this.handleKeyDown = (e) => {
const { keyCode: r, ctrlKey: o, metaKey: h } = e;
if (r === 84) {
const n = F();
this.calculateFocusFromValue = !1, this.setState({ focusedDate: n, navigateDate: n });
}
if ((o || h) && (r === O.left && this.handlePrevButtonClick(), r === O.right && this.handleNextButtonClick()), r === O.enter) {
const n = {
syntheticEvent: e,
nativeEvent: e.nativeEvent,
value: this.focusedDate,
target: this
};
this.handleDateChange(n);
} else {
const n = x(
this.navigation.move(
this.focusedDate,
this.navigation.action(e),
this.state.activeView,
this.service,
e
),
this.min,
this.max
);
if (P(this.focusedDate, n))
return;
this.dates && this.service && !this.service.isInArray(n, this.dates) && this.setState({ navigateDate: n }), this.calculateFocusFromValue = !1, this.setState({ focusedDate: n });
}
e.preventDefault();
}, this.handleViewChange = ({ view: e }) => {
this.calculateFocusFromValue = !1, this.setState((t) => ({ activeView: e, navigateDate: t.focusedDate }));
}, this.handleWeekSelection = (e, t, r) => {
if (this.props.mode === "single")
return;
const o = 0, h = 6, n = t === o ? e : M(e, -t), p = t === h ? e : M(e, h - t);
let f = null;
if (this.props.mode === "multiple") {
f = [];
for (let y = o; y <= h; y++)
f.push(M(n, y));
this.setState({ value: f, focusedDate: e });
}
this.props.mode === "range" && (f = { start: n, end: p }, this.setState({ value: f, focusedDate: e }));
const { onChange: C } = this.props;
if (C) {
const y = {
syntheticEvent: r,
nativeEvent: r.nativeEvent,
value: f,
target: this
};
C.call(void 0, y);
}
}, this.handleDateChange = (e) => {
const t = m(e.value), r = this.bus.canMoveDown(this.state.activeView);
if (this.props.disabled)
return;
if (r)
if (e.isTodayClick)
this.bus.moveToBottom(this.state.activeView);
else {
this.bus.moveDown(this.state.activeView, e.syntheticEvent), this.setState({ focusedDate: t, navigateDate: t });
return;
}
this.calculateFocusFromValue = !0;
let o;
switch (this.props.mode) {
case "single":
o = m(e.value);
break;
case "multiple":
if (Array.isArray(this.selectedMultiple)) {
const n = this.selectedMultiple.slice();
let p = -1;
n.forEach((f, C) => {
P(f, e.value) && (p = C);
}), p !== -1 ? n.splice(p, 1) : n.push(m(e.value)), o = n.slice();
} else
this.selectedDate ? o = [m(this.selectedDate), m(e.value)] : o = [m(e.value)];
break;
case "range": {
o = this.selectedRange.start !== null && this.selectedRange.end !== null && this.activeRange === "start" ? this.clampRange(e.value) : this.generateRange(e.value, this.selectedRange), this.activeRangeEnd = this.activeRange !== "end" ? "end" : "start";
break;
}
default:
o = m(e.value);
break;
}
this.valueDuringOnChange = o, e.isTodayClick && this.setState({ navigateDate: t }), this.setState({ value: o, focusedDate: t }), this.valueDuringOnChange = o;
const { onChange: h } = this.props;
if (h) {
const n = {
syntheticEvent: e.syntheticEvent,
nativeEvent: e.nativeEvent,
value: o,
target: this
};
h.call(void 0, n);
}
this.valueDuringOnChange = void 0;
}, this.showLicenseWatermark = !Q(z, { component: "MultiViewCalendar" }), this.licenseMessage = Z(z);
const a = i.value !== void 0 ? i.value : i.defaultValue || u.defaultProps.defaultValue, c = S(this.min, this.max, a), w = U(this.min, this.max, a), R = $(a), I = H(c, w, R), V = _(
A[i.defaultActiveView],
this.bottomView,
this.topView
), b = x(i.focusedDate || I || F(), this.min, this.max);
this.state = {
value: a,
activeView: V,
focusedDate: b,
navigateDate: b
}, this.activeRangeEnd = pe(R, c), this.bus = new ce(this.handleViewChange), this.navigation = new de(this.bus), this.calculateFocusFromValue = !1, this.lastView = V, this.lastViewsCount = this.props.views || E.defaultProps.views;
}
get wrapperID() {
return this.props.id + "-wrapper-id";
}
get isRtl() {
return this.props.dir === "rtl";
}
/**
* Gets the wrapping element of the MultiViewCalendar component.
*/
get element() {
return this._element;
}
/**
* Gets the value of the MultiViewCalendar.
*/
get value() {
return this.valueDuringOnChange !== void 0 ? this.valueDuringOnChange : this.props.value !== void 0 ? this.props.value : this.state.value;
}
/**
* Gets the current focused date of the MultiViewCalendar.
*/
get focusedDate() {
return m(this._focusedDate);
}
get min() {
return g(
this.props.min !== void 0 ? this.props.min : u.defaultProps.min
);
}
get max() {
return g(
this.props.max !== void 0 ? this.props.max : u.defaultProps.max
);
}
get bottomView() {
return A[this.props.bottomView !== void 0 ? this.props.bottomView : u.defaultProps.bottomView];
}
get topView() {
return A[this.props.topView !== void 0 ? this.props.topView : u.defaultProps.topView];
}
get activeRange() {
return this.props.activeRangeEnd !== void 0 ? this.props.activeRangeEnd : this.activeRangeEnd;
}
get todayIsInRange() {
return T(F(), g(this.min), g(this.max));
}
/**
* @hidden
*/
componentDidMount() {
this.calculateFocusFromValue = !0;
}
/**
* @hidden
*/
componentDidUpdate() {
this.calendarViewList && (this.isActive ? this.calendarViewList.focusActiveDate : this.calendarViewList.blurActiveDate)();
const i = S(this.min, this.max, this.value);
this.calculateFocusFromValue = !!(this.selectedDate && i && this.selectedDate.getTime() && i.getTime()), this.lastView = this.state.activeView, this.lastViewsCount = this.props.views || E.defaultProps.views;
}
/**
* @hidden
*/
render() {
this.props._ref && this.props._ref(this), this.intl = G(this), this.localization = X(this), this.bus.configure(this.bottomView, this.topView);
const i = _(this.state.activeView, this.bottomView, this.topView);
this.service = this.bus.service(i, this.intl), this.selectedDate = S(this.min, this.max, this.value), this.selectedMultiple = U(this.min, this.max, this.value), this.selectedRange = $(this.value);
const a = H(this.selectedDate, this.selectedMultiple, this.selectedRange);
this._focusedDate = x(
this.calculateFocusFromValue && a !== null ? a : this.state.focusedDate,
this.min,
this.max
);
const c = ee(
"k-calendar k-calendar-range k-calendar-md",
{
"k-disabled": this.props.disabled
},
this.props.className
), w = this.rangeWithFocused(this.selectedRange, this.focusedDate), R = this.localization.toLanguageString(K, Y[K]), I = this.localization.toLanguageString(W, Y[W]), V = !this.canNavigate(k.PrevView), b = !this.canNavigate(k.NextView), e = { "aria-disabled": V }, t = { "aria-disabled": b }, r = this.lastView !== i, o = this.dates && this.isInMonth(this.state.navigateDate, this.dates[0]), h = this.lastViewsCount !== this.props.views;
(!o || r || h) && (this.dates = this.service.datesList(
this.state.navigateDate,
this.props.views || E.defaultProps.views
));
const n = m(this.dates && this.dates[0] ? this.dates[0] : F());
return /* @__PURE__ */ d.createElement(
"div",
{
ref: (p) => {
this._element = p;
},
className: c,
id: this.props.id || this.wrapperID,
"aria-labelledby": this.props.ariaLabelledBy,
"aria-describedby": this.props.ariaDescribedBy,
tabIndex: this.props.disabled ? void 0 : this.props.tabIndex,
onFocus: this.handleFocus,
onBlur: this.handleBlur,
onMouseDown: this.handleMouseDown,
onClick: this.handleClick,
onKeyDown: this.handleKeyDown,
"aria-disabled": this.props.disabled,
dir: this.props.dir
},
/* @__PURE__ */ d.createElement(
re,
{
key: `.kendo.calendar.header.${n.getTime()}`,
activeView: i,
currentDate: n,
min: this.min,
max: this.max,
rangeLength: this.props.views,
bus: this.bus,
service: this.service,
headerTitle: this.props.headerTitle,
verticalView: this.props.mobileMode,
commands: /* @__PURE__ */ d.createElement(d.Fragment, null, /* @__PURE__ */ d.createElement(
L,
{
type: "button",
className: "k-calendar-nav-prev",
icon: this.isRtl ? "chevron-right" : "chevron-left",
svgIcon: this.isRtl ? N : B,
fillMode: "flat",
title: R,
disabled: V,
onClick: this.handlePrevButtonClick,
...e
}
), /* @__PURE__ */ d.createElement(
ue,
{
min: this.min,
max: this.max,
onClick: this.handleTodayClick,
disabled: !this.todayIsInRange
}
), /* @__PURE__ */ d.createElement(
L,
{
type: "button",
className: "k-calendar-nav-next",
icon: this.isRtl ? "chevron-left" : "chevron-right",
svgIcon: this.isRtl ? B : N,
fillMode: "flat",
title: I,
disabled: b,
onClick: this.handleNextButtonClick,
...t
}
))
}
),
/* @__PURE__ */ d.createElement(
E,
{
ref: (p) => {
this.calendarViewList = p;
},
dates: this.dates,
activeView: i,
focusedDate: this.focusedDate,
weekDaysFormat: this.props.weekDaysFormat,
min: this.min,
max: this.max,
bus: this.bus,
service: this.service,
selectionRange: w,
value: this.selectedMultiple || this.selectedDate,
cellUID: this.cellUID,
views: this.props.views,
onChange: this.handleDateChange,
onWeekSelect: this.handleWeekSelection,
showWeekNumbers: this.props.weekNumber,
onCellEnter: this.handleCellEnter,
cell: this.props.cell,
weekCell: this.props.weekCell,
headerTitle: this.props.headerTitle,
verticalView: this.props.mobileMode,
showOtherMonthDays: this.props.showOtherMonthDays,
allowReverse: this.props.allowReverse
}
),
this.showLicenseWatermark && /* @__PURE__ */ d.createElement(te, { message: this.licenseMessage })
);
}
// protected isListInRange = (list: Date[]): boolean => {
// return this.min < list[0]
// && this.max > list[Math.max(0, (this.props.views || MultiViewCalendarWithoutContext.defaultProps.views) - 1)];
// };
isInMonth(i, a) {
return !!a && ne(a) <= i && i <= oe(a);
}
};
u.displayName = "MultiViewCalendar", u.propTypes = {
activeRangeEnd: s.oneOf(["start", "end"]),
allowReverse: s.bool,
bottomView: s.oneOf(["month", "year", "decade", "century"]),
className: s.string,
defaultActiveView: s.oneOf(["month", "year", "decade", "century"]),
defaultValue: s.oneOfType([
D(s.instanceOf(Date)),
s.arrayOf(s.instanceOf(Date)),
s.shape({
start: D(s.instanceOf(Date)),
end: D(s.instanceOf(Date))
})
]),
disabled: s.bool,
focusedDate: s.instanceOf(Date),
id: s.string,
weekDaysFormat: s.oneOf(["narrow", "short", "abbreviated"]),
ariaLabelledBy: s.string,
ariaDescribedBy: s.string,
max: s.instanceOf(Date),
min: s.instanceOf(Date),
mode: s.oneOf(["single", "multiple", "range"]),
onBlur: s.func,
onChange: s.func,
onFocus: s.func,
tabIndex: s.number,
topView: s.oneOf(["month", "year", "decade", "century"]),
value: s.oneOfType([
D(s.instanceOf(Date)),
s.arrayOf(s.instanceOf(Date)),
s.shape({
start: D(s.instanceOf(Date).isRequired),
end: D(s.instanceOf(Date).isRequired)
})
]),
views: (i, a, c) => {
const w = i[a];
return w !== void 0 && w < 1 ? new Error(
`Invalid prop '${a}' supplied to'${c}'. The '${a}' property cannot be less than 1'`
) : null;
},
weekNumber: s.bool,
showOtherMonthDays: s.bool,
dir: s.string
}, u.defaultProps = {
disabled: !1,
min: le,
max: he,
navigation: !0,
defaultActiveView: "month",
defaultValue: null,
topView: "century",
weekDaysFormat: "short",
tabIndex: 0,
bottomView: "month",
views: 2,
allowReverse: !1,
showOtherMonthDays: !1
};
let v = u;
const me = se(), ve = ie(
ae(
me,
v
)
);
ve.displayName = "KendoReactMultiViewCalendar";
q(v);
J(v);
export {
ve as MultiViewCalendar,
me as MultiViewCalendarPropsContext,
v as MultiViewCalendarWithoutContext
};