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