UNPKG

@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
/** * @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 };