UNPKG

@progress/kendo-react-dateinputs

Version:

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

501 lines (500 loc) 16.9 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 e from "prop-types"; import { Popup as X } from "@progress/kendo-react-popup"; import { cloneDate as y } from "@progress/kendo-date-math"; import { classNames as c, uTimePicker as g, Keys as d, validatePackage as Z, canUseDOM as I, AsyncFocusBlur as J, WatermarkOverlay as Q, createPropsContext as Y, withIdHOC as $, withPropsContext as ee, withUnstyledHOC as te, withAdaptiveModeContext as ie } from "@progress/kendo-react-common"; import { clockIcon as se } from "@progress/kendo-svg-icons"; import { provideLocalizationService as oe, registerForLocalization as ne } from "@progress/kendo-react-intl"; import { packageMetadata as ae } from "../package-metadata.mjs"; import { toggleClock as f, messages as u, timePickerCancel as re, timePickerSet as C, toggleTimeSelector as T } from "../messages/index.mjs"; import { DateInput as le } from "../dateinput/DateInput.mjs"; import { TimeSelector as he } from "./TimeSelector.mjs"; import { MAX_TIME as de, MIN_TIME as ue, setTime as M, MIDNIGHT_DATE as pe } from "../utils.mjs"; import { isInRange as me, isBiggerThanMax as ce, isSmallerThanMin as ge } from "./utils.mjs"; import { PickerFloatingLabel as fe } from "../hooks/usePickerFloatingLabel.mjs"; import { Button as ve } from "@progress/kendo-react-buttons"; import { AdaptiveMode as we } from "../common/AdaptiveMode.mjs"; import { ActionSheetContent as Se } from "@progress/kendo-react-layout"; const a = class a extends n.Component { constructor(i) { super(i), this._element = null, this._dateInput = n.createRef(), this._timeSelector = null, this.shouldFocusDateInput = !1, this.prevShow = !1, this.showLicenseWatermark = !1, this.focus = () => { this.dateInput && this.dateInput.focus(); }, this.renderTimeSelector = () => { const { smoothScroll: t, cancelButton: s, nowButton: o, disabled: l, format: h, steps: r, unstyled: m } = this.props; return /* @__PURE__ */ n.createElement( he, { ref: this.setTimeSelectorRef, mobileMode: this.mobileMode, show: this.show, cancelButton: s, disabled: l, nowButton: o, format: h, min: this.min, max: this.max, steps: r, smoothScroll: t, value: this.value, footer: !this.mobileMode, handleTimeChange: this.mobileMode && this.handleTimeChange, onChange: this.handleValueChange, onReject: this.handleValueReject, unstyled: m } ); }, this.renderPopup = () => { const { popupClass: t, ...s } = this.popupSettings, { unstyled: o } = this.props, l = o && o.uTimePicker, h = c(t), r = { popupClass: g.popup({ c: l }), show: this.show, animate: this.element !== null, anchor: this.element, className: h, id: this._popupId, anchorAlign: { horizontal: "left", vertical: "bottom" }, popupAlign: { horizontal: "left", vertical: "top" }, ...s }; return this.props.popup ? /* @__PURE__ */ n.createElement(this.props.popup, { ...r }, this.renderTimeSelector()) : /* @__PURE__ */ n.createElement(X, { ...r }, this.renderTimeSelector()); }, this.renderAdaptivePopup = () => { const { windowWidth: t = 0 } = this.state, s = { expand: this.show, onClose: this.handleBlur, title: this.props.adaptiveTitle, windowWidth: t, footer: { cancelText: this.localizationService.toLanguageString(f, u[re]), onCancel: this.handleValueReject, applyText: this.localizationService.toLanguageString(C, u[C]), onApply: (o) => this.handleValueChange(o) } }; return /* @__PURE__ */ n.createElement(we, { ...s }, /* @__PURE__ */ n.createElement(Se, { overflowHidden: !0 }, this.renderTimeSelector())); }, this.setTimeSelectorRef = (t) => { this._timeSelector = t; }, this.nextValue = (t, s) => t.value !== void 0 ? t.value : s.value, this.nextShow = (t, s) => t.show !== void 0 ? t.show : s.show, this.handleInputValueChange = (t) => { const s = this.mergeTime(t.value); this.handleValueChange({ ...t, value: s }); }, this.handleTimeChange = (t) => { this.setState({ candidate: t.time }); }, this.handleValueChange = (t) => { this.setState({ value: y(t.value || this.state.candidate) }), this.valueDuringOnChange = t.value, this.showDuringOnChange = !1, this.shouldFocusDateInput = !0; const { onChange: s } = this.props, o = this.state.candidate || this.value; s && s.call(void 0, { syntheticEvent: t.syntheticEvent, nativeEvent: t.nativeEvent, value: o, 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.handleValueReject = (t) => { this.setShow(!1); }, this.handleIconClick = (t) => { this.props.disabled || (this.shouldFocusDateInput = !0, this.setShow(!this.show)); }, this.handleIconMouseDown = (t) => { t.preventDefault(); }, this.handleKeyDown = (t) => { const { altKey: s, keyCode: o } = t; if (o === d.esc) { this.shouldFocusDateInput = !0, this.setShow(!1); return; } s && (o === d.up || o === d.down) && (t.preventDefault(), t.stopPropagation(), this.shouldFocusDateInput = o === d.up, this.setShow(o === d.down)); }, this.showLicenseWatermark = !Z(ae, { component: "TimePicker" }), this.state = { value: this.props.defaultValue || a.defaultProps.defaultValue, show: this.props.defaultShow || a.defaultProps.defaultShow, focused: !1, candidate: null }, this.normalizeTime = this.normalizeTime.bind(this), this.setShow = this.setShow.bind(this), this.mergeTime = this.mergeTime.bind(this); } get _popupId() { return this.props.id + "-popup-id"; } get document() { if (I) return this.element && this.element.ownerDocument || document; } /** * Gets the wrapping element of the TimePicker. */ get element() { return this._element; } /** * Gets the DateInput component inside the TimePicker component. */ get dateInput() { return this._dateInput.current; } /** * Gets the TimeSelector component inside the TimePicker component. */ get timeSelector() { return this._timeSelector; } /** * Gets the value of the TimePicker. */ get value() { const i = this.valueDuringOnChange !== void 0 ? this.valueDuringOnChange : this.props.value !== void 0 ? this.props.value : this.state.value; return i !== null ? y(i) : null; } /** * Gets the popup state of the TimeSelector. */ 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 TimePicker. */ get name() { return this.props.name; } /** * Represents the validity state into which the TimePicker is set. */ get validity() { const i = this.value && this.normalizeTime(this.value), t = this.normalizeTime(this.min), s = this.normalizeTime(this.max), o = me(i, t, s), l = this.props.validationMessage !== void 0, h = (!this.required || this.value !== null) && o, r = this.props.valid !== void 0 ? this.props.valid : h; return { customError: l, rangeOverflow: ce(i, s), rangeUnderflow: ge(i, t), valid: r, valueMissing: this.value === null }; } /** * The mobile mode of the ComboBox. */ 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); } /** * @hidden */ get validityStyles() { return this.props.validityStyles !== void 0 ? this.props.validityStyles : a.defaultProps.validityStyles; } /** * @hidden */ get required() { return this.props.required !== void 0 ? this.props.required : !1; } get popupSettings() { return this.props.popupSettings || a.defaultProps.popupSettings; } get min() { return this.props.min !== void 0 ? this.props.min : a.defaultProps.min; } get max() { return this.props.max !== void 0 ? this.props.max : a.defaultProps.max; } get dateInputComp() { return this.props.dateInput || a.defaultProps.dateInput; } get localizationService() { return oe(this); } /** * @hidden */ componentDidMount() { var i; this.observerResize = I && 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() { this._timeSelector && this.show && !this.prevShow ? this._timeSelector.focusActiveList() : this.dateInput && this.dateInput.element && !this.show && this.shouldFocusDateInput && this.dateInput.element.focus({ preventScroll: !0 }), this.prevShow = this.show, this.shouldFocusDateInput = !1; } /** * @hidden */ componentWillUnmount() { var i; (i = this.document) != null && i.body && this.observerResize && this.observerResize.disconnect(); } /** * @hidden */ render() { const { size: i = a.defaultProps.size, rounded: t = a.defaultProps.rounded, fillMode: s = a.defaultProps.fillMode, disabled: o, tabIndex: l, title: h, id: r, className: m, format: O, formatPlaceholder: D, width: P, name: z, steps: k, validationMessage: x, required: E, validityStyles: R, ariaLabelledBy: B, ariaDescribedBy: V, unstyled: v, enableMouseWheel: A, autoCorrectParts: F, autoSwitchParts: L, autoSwitchKeys: N, allowCaretMode: _, inputAttributes: q } = this.props, w = v && v.uTimePicker, S = !this.validityStyles || this.validity.valid, K = { disabled: o, format: O, formatPlaceholder: D, id: r, ariaLabelledBy: B, ariaDescribedBy: V, max: this.normalizeTime(this.max), min: this.normalizeTime(this.min), name: z, onChange: this.handleInputValueChange, required: E, steps: k, tabIndex: this.show ? -1 : l, title: h, valid: this.validity.valid, validationMessage: x, validityStyles: R, value: this.value && this.normalizeTime(this.value), label: void 0, placeholder: this.state.focused ? null : this.props.placeholder, ariaHasPopup: "dialog", ariaExpanded: this.show, size: null, fillMode: null, rounded: null, enableMouseWheel: A, autoCorrectParts: F, autoSwitchParts: L, autoSwitchKeys: N, allowCaretMode: _, inputAttributes: q }, W = this.localizationService.toLanguageString(f, u[f]), U = this.localizationService.toLanguageString( T, u[T] ), b = /* @__PURE__ */ n.createElement( J, { onFocus: this.handleFocus, onBlur: this.mobileMode ? void 0 : this.handleBlur, onSyncBlur: this.props.onBlur, onSyncFocus: this.props.onFocus }, ({ onFocus: j, onBlur: H }) => /* @__PURE__ */ n.createElement(n.Fragment, null, /* @__PURE__ */ n.createElement( "span", { id: this.props.id, ref: (G) => { this._element = G; }, className: c( g.wrapper({ c: w, size: i, rounded: t, fillMode: s, invalid: !S, required: this.required, disabled: o }), m ), onKeyDown: this.handleKeyDown, style: { width: P }, onFocus: j, onBlur: H, onClick: this.mobileMode ? this.handleIconClick : void 0 }, /* @__PURE__ */ n.createElement( this.dateInputComp, { _ref: this._dateInput, ariaRole: "combobox", ariaControls: this._popupId, ...K } ), /* @__PURE__ */ n.createElement( ve, { tabIndex: -1, type: "button", icon: "clock", svgIcon: se, onMouseDown: this.handleIconMouseDown, onClick: this.mobileMode ? void 0 : this.handleIconClick, title: U, className: c(g.inputButton({ c: w })), rounded: null, fillMode: s, "aria-label": W } ), !this.mobileMode && this.renderPopup() ), this.mobileMode && this.renderAdaptivePopup(), this.showLicenseWatermark && /* @__PURE__ */ n.createElement(Q, null)) ); return this.props.label ? /* @__PURE__ */ n.createElement( fe, { dateInput: this._dateInput, label: this.props.label, editorId: r, editorValid: S, editorDisabled: this.props.disabled, children: b, style: { width: this.props.width } } ) : b; } normalizeTime(i) { return M(pe, i); } 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 })); } mergeTime(i) { return this.value && i ? M(this.value, i) : i; } calculateMedia(i) { for (const t of i) this.setState({ windowWidth: t.target.clientWidth }); } }; a.displayName = "TimePicker", a.propTypes = { className: e.string, cancelButton: e.bool, nowButton: e.bool, defaultShow: e.bool, defaultValue: e.instanceOf(Date), disabled: e.bool, 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, steps: e.shape({ hour: e.number, minute: e.number, second: e.number }), smoothScroll: e.bool, tabIndex: e.number, title: e.string, value: e.instanceOf(Date), width: e.oneOfType([e.number, e.string]), validationMessage: e.string, required: e.bool, validate: e.bool, valid: e.bool, size: e.oneOf([null, "small", "medium", "large"]), rounded: e.oneOf([null, "small", "medium", "large", "full"]), fillMode: e.oneOf([null, "solid", "flat", "outline"]), inputAttributes: e.object }, a.defaultProps = { defaultShow: !1, defaultValue: null, disabled: !1, format: "t", max: de, min: ue, popupSettings: {}, tabIndex: 0, steps: {}, validityStyles: !0, dateInput: le, size: "medium", rounded: "medium", fillMode: "solid" }; let p = a; const be = Y(), ye = $( ee( be, te(ie(p)) ) ); ye.displayName = "KendoReactTimePicker"; ne(p); export { ye as TimePicker, be as TimePickerPropsContext, p as TimePickerWithoutContext };