UNPKG

@progress/kendo-react-dateinputs

Version:

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

512 lines (511 loc) 16.4 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 a from "react"; import e from "prop-types"; import { Popup as $ } from "@progress/kendo-react-popup"; import { cloneDate as M } from "@progress/kendo-date-math"; import { Keys as d, canUseDOM as O, AsyncFocusBlur as ee, classNames as I, uDateTimePicker as D, createPropsContext as te, withIdHOC as ie, withPropsContext as se, withUnstyledHOC as oe, withAdaptiveModeContext as ne } from "@progress/kendo-react-common"; import { calendarIcon as ae } from "@progress/kendo-svg-icons"; import { DateInput as re } from "../dateinput/DateInput.mjs"; import { Button as le } from "@progress/kendo-react-buttons"; import { MAX_DATE as he, MIN_DATE as de, isInDateRange as ue, MAX_TIME as pe, MIN_TIME as ce } from "../utils.mjs"; import { dateTimePickerCancel as C, messages as p, dateTimePickerSet as P, toggleDateTimeSelector as c } from "../messages/index.mjs"; import { provideLocalizationService as m, registerForLocalization as me } from "@progress/kendo-react-intl"; import { DateTimeSelector as fe } from "./DateTimeSelector.mjs"; import { isInTimeRange as ge } from "../timepicker/utils.mjs"; import { PickerFloatingLabel as ve } from "../hooks/usePickerFloatingLabel.mjs"; import { AdaptiveMode as we } from "../common/AdaptiveMode.mjs"; import { ActionSheetContent as be } from "@progress/kendo-react-layout"; const o = class o extends a.Component { constructor(i) { super(i), this._element = null, this._dateInput = a.createRef(), this._dateTimeSelector = null, this.shouldFocusDateInput = !1, this.prevShow = !1, this.focus = () => { const t = this.dateInputElement(); t && t.focus(); }, this.renderPicker = () => { const { disabled: t, minTime: s, maxTime: n, format: h, calendar: l, cancelButton: r, weekNumber: g, focusedDate: u, unstyled: v } = this.props; return /* @__PURE__ */ a.createElement( fe, { ref: (w) => { this._dateTimeSelector = w; }, cancelButton: r, steps: this.props.steps, value: this.value, onChange: this.handleValueChange, onReject: this.handleReject, disabled: t, weekNumber: g, min: this.min, max: this.max, minTime: s, maxTime: n, focusedDate: u, format: h, calendar: l, mobileMode: this.mobileMode, footerActions: !this.mobileMode, unstyled: v } ); }, this.renderAdaptivePopup = () => { const { windowWidth: t = 0 } = this.state, s = m(this).toLanguageString( C, p[C] ), n = m(this).toLanguageString( P, p[P] ), h = { expand: this.show, onClose: this.handleBlur, title: this.props.adaptiveTitle, windowWidth: t, footer: { cancelText: s, onCancel: (l) => { var r; return (r = this._dateTimeSelector) == null ? void 0 : r.handleReject(l); }, applyText: n, onApply: (l) => { var r; return (r = this._dateTimeSelector) == null ? void 0 : r.handleAccept(l); } } }; return /* @__PURE__ */ a.createElement(we, { ...h }, /* @__PURE__ */ a.createElement(be, { overflowHidden: !0 }, this.renderPicker())); }, this.handleReject = () => { this.shouldFocusDateInput = !0, this.setShow(!1); }, this.handleValueChange = (t) => { this.setState({ value: M(t.value || void 0) }), this.valueDuringOnChange = t.value, this.showDuringOnChange = !1, this.mobileMode || (this.shouldFocusDateInput = !0); const { onChange: s } = this.props; s && s.call(void 0, { syntheticEvent: t.syntheticEvent, nativeEvent: t.nativeEvent, value: this.value, show: this.show, target: this }), this.valueDuringOnChange = void 0, this.showDuringOnChange = void 0, this.setShow(!1); }, this.handleFocus = () => { this.setState({ focused: !0 }); }, this.handleBlur = () => { this.setState({ focused: !1 }), this.setShow(!1); }, this.handleDateIconClick = () => { this.props.disabled || (this.shouldFocusDateInput = !0, this.setShow(!this.show)); }, this.handleIconMouseDown = (t) => { t.preventDefault(); }, this.handleKeyDown = (t) => { const { altKey: s, keyCode: n } = t; if (n === d.esc) { this.shouldFocusDateInput = !0, this.setShow(!1); return; } s && (n === d.up || n === d.down) && (t.preventDefault(), t.stopPropagation(), this.shouldFocusDateInput = n === d.up, this.setShow(n === d.down)); }, this.dateInputElement = () => this.dateInput && this.dateInput.element || this.element && this.element.querySelector(".k-dateinput > input.k-input-inner"), this.state = { value: this.props.defaultValue || o.defaultProps.defaultValue, show: this.props.defaultShow || o.defaultProps.defaultShow, focused: !1 }; } get _popupId() { return this.props.id + "-popup-id"; } get document() { if (O) return this.element && this.element.ownerDocument || document; } /** * Gets the wrapping element of the DateTimePicker. */ get element() { return this._element; } /** * Gets the DateInput component inside the DateTimePicker component. */ get dateInput() { return this._dateInput.current; } /** * Gets the value of the DateTimePicker. */ get value() { const i = this.valueDuringOnChange !== void 0 ? this.valueDuringOnChange : this.props.value !== void 0 ? this.props.value : this.state.value; return i !== null ? M(i) : null; } /** * Gets the popup state of the DateTimePicker. */ get show() { return this.showDuringOnChange !== void 0 ? this.showDuringOnChange : this.props.show !== void 0 ? this.props.show : this.state.show; } /** * Gets the `name` property of the DateTimePicker. */ get name() { return this.props.name; } /** * The mobile mode of the DateTimePicker. */ get mobileMode() { var t; return !!(this.state.windowWidth && this.props._adaptiveMode && this.state.windowWidth <= ((t = this.props._adaptiveMode) == null ? void 0 : t.medium) && this.props.adaptive); } get min() { return this.props.min !== void 0 ? this.props.min : o.defaultProps.min; } get max() { return this.props.max !== void 0 ? this.props.max : o.defaultProps.max; } /** * Represents the validity state into which the DateTimePicker is set. */ get validity() { const i = ue(this.value, this.min, this.max) && ge(this.value, this.props.minTime || ce, this.props.maxTime || pe), t = this.props.validationMessage !== void 0, s = (!this.required || this.value !== null) && i, n = this.props.valid !== void 0 ? this.props.valid : s; return { customError: t, rangeOverflow: this.value && this.max.getTime() < this.value.getTime() || !1, rangeUnderflow: this.value && this.value.getTime() < this.min.getTime() || !1, valid: n, valueMissing: this.value === null }; } /** * @hidden */ get validityStyles() { return this.props.validityStyles !== void 0 ? this.props.validityStyles : o.defaultProps.validityStyles; } /** * @hidden */ get required() { return this.props.required !== void 0 ? this.props.required : !1; } /** * @hidden */ get dateInputComp() { return this.props.dateInput || o.defaultProps.dateInput; } /** * @hidden */ componentDidMount() { var i; this.observerResize = O && window.ResizeObserver && new window.ResizeObserver(this.calculateMedia.bind(this)), this.show && this.forceUpdate(), (i = this.document) != null && i.body && this.observerResize && this.observerResize.observe(this.document.body); } /** * @hidden */ componentDidUpdate() { const i = this.dateInputElement(); this._dateTimeSelector && this.show && !this.prevShow && this._dateTimeSelector.focus({ preventScroll: !0 }), i && !this.show && this.shouldFocusDateInput && i.focus({ preventScroll: !0 }), this.prevShow = this.show, this.shouldFocusDateInput = !1; } /** * @hidden */ componentWillUnmount() { var i; clearTimeout(this.nextTickId), (i = this.document) != null && i.body && this.observerResize && this.observerResize.disconnect(); } /** * @hidden */ render() { const { size: i = o.defaultProps.size, rounded: t = o.defaultProps.rounded, fillMode: s = o.defaultProps.fillMode, autoFocus: n = o.defaultProps.autoFocus, inputAttributes: h, disabled: l, tabIndex: r, title: g, id: u, format: v, formatPlaceholder: w, min: x, max: k, className: E, width: F, name: A, validationMessage: R, required: z, validityStyles: B, minTime: N, maxTime: V, ariaLabelledBy: _, ariaDescribedBy: q, popup: L = $, unstyled: b, autoFill: K, twoDigitYearMax: U, enableMouseWheel: j, autoCorrectParts: H, autoSwitchParts: W, autoSwitchKeys: X, allowCaretMode: Y } = this.props, y = b && b.uDateTimePicker, S = !this.validityStyles || this.validity.valid, Z = { id: u, ariaLabelledBy: _, ariaDescribedBy: q, format: v, formatPlaceholder: w, disabled: l, title: g, validityStyles: B, validationMessage: R, required: z, min: x, max: k, minTime: N, maxTime: V, name: A, tabIndex: this.show ? -1 : r, valid: this.validity.valid, value: this.value, onChange: this.handleValueChange, steps: this.props.steps, label: void 0, placeholder: this.state.focused ? null : this.props.placeholder, ariaExpanded: this.show, size: null, fillMode: null, rounded: null, unstyled: b, autoFill: K, twoDigitYearMax: U, enableMouseWheel: j, autoCorrectParts: H, autoSwitchParts: W, autoSwitchKeys: X, allowCaretMode: Y }, T = /* @__PURE__ */ a.createElement( ee, { onFocus: this.handleFocus, onBlur: this.handleBlur, onSyncFocus: this.props.onFocus, onSyncBlur: this.props.onBlur }, ({ onFocus: G, onBlur: J }) => /* @__PURE__ */ a.createElement(a.Fragment, null, /* @__PURE__ */ a.createElement( "div", { ref: (Q) => { this._element = Q; }, className: I( D.wrapper({ c: y, size: i, fillMode: s, rounded: t, disabled: l, required: this.required, invalid: !S }), E ), onKeyDown: this.handleKeyDown, style: { width: F }, onFocus: this.mobileMode ? void 0 : G, onBlur: J, onClick: this.mobileMode ? this.handleDateIconClick : void 0 }, /* @__PURE__ */ a.createElement( this.dateInputComp, { _ref: this._dateInput, ariaRole: "combobox", ariaControls: this._popupId, ariaHasPopup: "dialog", autoFocus: n, inputAttributes: h, ...Z } ), /* @__PURE__ */ a.createElement( le, { tabIndex: -1, type: "button", icon: "calendar", svgIcon: ae, onMouseDown: this.handleIconMouseDown, onClick: this.mobileMode ? void 0 : this.handleDateIconClick, title: m(this).toLanguageString( c, p[c] ), className: I(D.inputButton({ c: y })), rounded: null, fillMode: s, "aria-label": m(this).toLanguageString( c, p[c] ) } ), /* @__PURE__ */ a.createElement( L, { show: this.show, animate: this.element !== null, anchor: this.element, popupClass: I(D.popup({ c: y })), id: this._popupId, anchorAlign: { horizontal: "left", vertical: "bottom" }, popupAlign: { horizontal: "left", vertical: "top" } }, !this.mobileMode && this.renderPicker() ) ), this.mobileMode && this.renderAdaptivePopup()) ); return this.props.label ? /* @__PURE__ */ a.createElement( ve, { dateInput: this._dateInput, label: this.props.label, editorId: u, editorValid: S, editorDisabled: this.props.disabled, children: T, style: { width: this.props.width } } ) : T; } setShow(i) { const { onOpen: t, onClose: s } = this.props; this.show !== i && (this.setState({ show: i }), i && t && t.call(void 0, { target: this }), !i && s && s.call(void 0, { target: this })); } nextTick(i) { clearTimeout(this.nextTickId), this.nextTickId = window.setTimeout(() => i()); } calculateMedia(i) { for (const t of i) this.setState({ windowWidth: t.target.clientWidth }); } }; o.displayName = "DateTimePicker", o.propTypes = { className: e.string, defaultShow: e.bool, defaultValue: e.instanceOf(Date), disabled: e.bool, focusedDate: e.instanceOf(Date), format: e.oneOfType([ e.string, e.shape({ skeleton: e.string, pattern: e.string, date: e.oneOf(["short", "medium", "long", "full"]), time: e.oneOf(["short", "medium", "long", "full"]), datetime: e.oneOf(["short", "medium", "long", "full"]), era: e.oneOf(["narrow", "short", "long"]), year: e.oneOf(["numeric", "2-digit"]), month: e.oneOf(["numeric", "2-digit", "narrow", "short", "long"]), day: e.oneOf(["numeric", "2-digit"]), weekday: e.oneOf(["narrow", "short", "long"]), hour: e.oneOf(["numeric", "2-digit"]), hour12: e.bool, minute: e.oneOf(["numeric", "2-digit"]), second: e.oneOf(["numeric", "2-digit"]), timeZoneName: e.oneOf(["short", "long"]) }) ]), formatPlaceholder: e.oneOfType([ e.oneOf([ "wide", "narrow", "short", "formatPattern" ]), e.shape({ year: e.string, month: e.string, day: e.string, hour: e.string, minute: e.string, second: e.string }) ]), id: e.string, ariaLabelledBy: e.string, ariaDescribedBy: e.string, min: e.instanceOf(Date), max: e.instanceOf(Date), name: e.string, popupSettings: e.shape({ animate: e.bool, appendTo: e.any, popupClass: e.string }), show: e.bool, tabIndex: e.number, title: e.string, value: e.instanceOf(Date), weekNumber: e.bool, width: e.oneOfType([e.number, e.string]), validationMessage: e.string, required: e.bool, validate: e.bool, valid: e.bool, cancelButton: e.bool, size: e.oneOf([null, "small", "medium", "large"]), rounded: e.oneOf([null, "small", "medium", "large", "full"]), fillMode: e.oneOf([null, "solid", "flat", "outline"]), autoFocus: e.bool, inputAttributes: e.object }, o.defaultProps = { defaultShow: !1, defaultValue: null, disabled: !1, format: "g", // general date and time pattern (short time): "M/d/y h:mm a" for en. max: he, min: de, popupSettings: {}, tabIndex: 0, weekNumber: !1, validityStyles: !0, cancelButton: !0, dateInput: re, size: "medium", rounded: "medium", fillMode: "solid", autoFocus: !1 }; let f = o; const ye = te(), Ie = ie( se( ye, oe( ne(f) ) ) ); Ie.displayName = "KendoReactDateTimePicker"; me(f); export { Ie as DateTimePicker, ye as DateTimePickerPropsContext, f as DateTimePickerWithoutContext };