UNPKG

@progress/kendo-react-dateinputs

Version:

React DateInput is a perfect input component for handling quick and efficient date values. KendoReact Date Inputs package

253 lines (252 loc) 8.63 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 n from "react"; import t from "prop-types"; import { cloneDate as O } from "@progress/kendo-date-math"; import { Keys as T, classNames as l, uTime as h, getActiveElement as R } from "@progress/kendo-react-common"; import { provideIntlService as k, provideLocalizationService as S, registerForIntl as C, registerForLocalization as M } from "@progress/kendo-react-intl"; import { selectNow as L, messages as x, now as I } from "../messages/index.mjs"; import { TimeList as P } from "./TimeList.mjs"; import { MIN_TIME as A, MAX_TIME as K, MIDNIGHT_DATE as _ } from "../utils.mjs"; import { TIME_PART as d } from "./models/TimePart.mjs"; import { isInTimeRange as $, getNow as z, snapTime as N, generateSnappers as B, timeInRange as W } from "./utils.mjs"; import { Button as j } from "@progress/kendo-react-buttons"; const v = new RegExp( `${d.hour}|${d.minute}|${d.second}|${d.dayperiod}|literal` ), a = class a extends n.Component { constructor(i) { super(i), this._element = null, this._nowButton = null, this.dateFormatParts = [], this.timeLists = [], this.focus = (s, e) => { Promise.resolve().then(() => { e && this._nowButton && this._nowButton.element && this._nowButton.element.focus(); const o = this.timeLists[0]; !e && this.state.activeListIndex === -1 && !this.hasActiveButton() && o && o.element && o.focus(s); }); }, this.timeFormatReducer = (s, e) => s + e.pattern, this.timeFormatFilter = (s, e, o) => { const r = e >= 1 && o[e - 1]; return r && r && s.type === "literal" ? v.test(r.type || "") : v.test(s.type || ""); }, this.focusList = (s) => { this.timeLists.length && this.timeLists.reduce(this.listReducer, []).map((e) => s === 1 ? e.next : e.prev).map((e) => e && e.element && e.element.focus({ preventScroll: !0 })); }, this.listReducer = (s, e, o, r) => s.length || e.props.id !== this.state.activeListIndex ? s : [ { next: r[o + 1] || e, prev: r[o - 1] || e } ], this.showNowButton = () => !this.hasSteps() && this.props.nowButton && $(z(), this.min, this.max), this.handleKeyDown = (s) => { const { keyCode: e } = s; switch (e) { case T.left: s.preventDefault(), this.focusList( 0 /* Left */ ); return; case T.right: s.preventDefault(), this.focusList( 1 /* Right */ ); return; default: return; } }, this.handleListBlur = () => { this.nextTick(() => { this.setState({ activeListIndex: -1 }); }); }, this.handleListFocus = (s) => { clearTimeout(this.nextTickId), this.setState({ activeListIndex: s }); }, this.handleChange = (s) => { const { onChange: e } = this.props; e && e.call(void 0, s); }, this.snapTime = N(B(this.props.steps, this.props.min || a.defaultProps.min)), this.state = { activeListIndex: -1 }, this.hasActiveButton = this.hasActiveButton.bind(this); } /** * @hidden */ get element() { return this._element; } get value() { return W(this.snapTime(O(this.props.value || _)), this.min, this.max); } get intl() { return k(this); } get min() { return this.snapTime(this.props.min || a.defaultProps.min); } get max() { return this.snapTime(this.props.max || a.defaultProps.max); } get steps() { return this.props.steps || a.defaultProps.steps; } get boundRange() { return this.props.boundRange !== void 0 ? this.props.boundRange : a.defaultProps.boundRange; } /** * @hidden */ componentWillUnmount() { clearTimeout(this.nextTickId); } componentDidMount() { const { onMount: i } = this.props; i && i.call(void 0, this.value); } /** * @hidden */ render() { const { format: i, smoothScroll: s, onNowClick: e, className: o, disabled: r, mobileMode: w, show: D, onNowKeyDown: E, unstyled: g } = this.props, m = g && g.uTime; this.snapTime = N(B(this.steps, this.min)), this.dateFormatParts = this.intl.splitDateFormat(i || a.defaultProps.format).filter(this.timeFormatFilter); const F = l( h.part({ c: m, mobileMode: w, disabled: r }), o ); this.timeLists = []; const b = S(this), y = b.toLanguageString(L, x[L]); return /* @__PURE__ */ n.createElement("div", { className: F }, /* @__PURE__ */ n.createElement("div", { className: l(h.header({ c: m })) }, /* @__PURE__ */ n.createElement("span", { className: l(h.title({ c: m })) }, this.intl.formatDate(this.value, this.dateFormatParts.reduce(this.timeFormatReducer, ""))), this.showNowButton() && /* @__PURE__ */ n.createElement( j, { type: "button", ref: (u) => { this._nowButton = u; }, className: l(h.now({ c: m })), fillMode: "flat", themeColor: "base", title: y, onKeyDown: E, "aria-label": y, onClick: e, tabIndex: r ? -1 : 0 }, b.toLanguageString(I, x[I]) )), /* @__PURE__ */ n.createElement("div", { className: l(h.listContainer({ c: m })), onKeyDown: this.handleKeyDown }, /* @__PURE__ */ n.createElement("span", { className: l(h.highlight({ c: m })) }), this.dateFormatParts.map((u, c) => u.type !== "literal" ? /* @__PURE__ */ n.createElement( "div", { key: c, className: l( h.listWrapper({ c: m, focused: c === this.state.activeListIndex }) ), role: "presentation", tabIndex: -1 }, /* @__PURE__ */ n.createElement( "span", { className: l(h.title({ c: m })), onMouseDown: (p) => { p.preventDefault(); } }, this.intl.dateFieldName(u) ), /* @__PURE__ */ n.createElement( P, { min: this.min, max: this.max, boundRange: this.boundRange, part: u, step: u.type ? this.steps[u.type] : 1, smoothScroll: s, ref: (p) => { p && this.timeLists.push(p); }, id: c, onFocus: () => { this.handleListFocus(c); }, onBlur: this.handleListBlur, onChange: this.handleChange, value: this.value, disabled: r, show: D, mobileMode: w, unstyled: g } ) ) : /* @__PURE__ */ n.createElement("div", { key: c, className: l(h.separator({ c: m })) }, u.pattern)))); } nextTick(i) { clearTimeout(this.nextTickId), this.nextTickId = window.setTimeout(() => i()); } hasActiveButton() { const i = R(document); return this._nowButton && i === this._nowButton.element; } hasSteps() { const i = Object.keys(this.steps); return i.length !== i.reduce((s, e) => s + this.steps[e], 0); } }; a.propTypes = { cancelButton: t.bool, disabled: t.bool, format: t.oneOfType([ t.string, t.shape({ skeleton: t.string, pattern: t.string, date: t.oneOf(["short", "medium", "long", "full"]), time: t.oneOf(["short", "medium", "long", "full"]), datetime: t.oneOf(["short", "medium", "long", "full"]), era: t.oneOf(["narrow", "short", "long"]), year: t.oneOf(["numeric", "2-digit"]), month: t.oneOf(["numeric", "2-digit", "narrow", "short", "long"]), day: t.oneOf(["numeric", "2-digit"]), weekday: t.oneOf(["narrow", "short", "long"]), hour: t.oneOf(["numeric", "2-digit"]), hour12: t.bool, minute: t.oneOf(["numeric", "2-digit"]), second: t.oneOf(["numeric", "2-digit"]), timeZoneName: t.oneOf(["short", "long"]) }) ]), max: t.instanceOf(Date), min: t.instanceOf(Date), nowButton: t.bool, steps: t.shape({ hour: t.number, minute: t.number, second: t.number }), smoothScroll: t.bool, tabIndex: t.number, value: t.instanceOf(Date), show: t.bool }, a.defaultProps = { value: null, disabled: !1, nowButton: !0, cancelButton: !0, format: "hh:mm a", min: A, max: K, steps: {}, boundRange: !1 }; let f = a; C(f); M(f); export { f as TimePart };