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