UNPKG

@progress/kendo-react-dateinputs

Version:

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

381 lines (380 loc) 13 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 r from "react"; import e from "prop-types"; import { cloneDate as D, isEqual as ke } from "@progress/kendo-date-math"; import { Button as $ } from "@progress/kendo-react-buttons"; import { caretAltUpIcon as _e, caretAltDownIcon as Fe } from "@progress/kendo-svg-icons"; import { useInternationalization as He, useLocalization as Be } from "@progress/kendo-react-intl"; import { useId as qe, useUnstyled as ze, usePropsContext as Q, classNames as h, uDateInput as O, createPropsContext as Ue, getActiveElement as ee } from "@progress/kendo-react-common"; import { FloatingLabel as We } from "@progress/kendo-react-labels"; import { DateInput as je } from "@progress/kendo-dateinputs-common"; import { DEFAULT_FORMAT as Ke, DEFAULT_FORMAT_PLACEHOLDER as Je, isInRange as Ye } from "./utils.mjs"; import { nullable as u, MAX_DATE as Xe, MIN_DATE as Ze, MIN_TIME as Ge, MAX_TIME as $e } from "../utils.mjs"; import { increaseValue as T, messages as M, decreaseValue as S } from "../messages/index.mjs"; import { isInTimeRange as Qe } from "../timepicker/utils.mjs"; import et from "../common/ClearButton.mjs"; import { DateInputIntl as tt } from "./dateInputIntl.mjs"; const nt = "Please enter a valid value!", ne = r.forwardRef((t, re) => { var G; const ae = qe(t.id), ie = He(), E = Be(), le = ze(), F = Q(te, t).unstyled || le, { format: P = l.format, size: oe = l.size, rounded: ue = l.rounded, fillMode: se = l.fillMode, formatPlaceholder: ce = l.formatPlaceholder, spinners: de = l.spinners, disabled: I = l.disabled, min: me = l.min, max: fe = l.max, minTime: ge = l.minTime, maxTime: ve = l.maxTime, validityStyles: ye = l.validityStyles, validationMessage: H = l.validationMessage, placeholder: f = l.placeholder, enableMouseWheel: be = l.enableMouseWheel, autoCorrectParts: he = l.autoCorrectParts, autoSwitchParts: Oe = l.autoSwitchParts, allowCaretMode: Ee = l.allowCaretMode, twoDigitYearMax: Ie = l.twoDigitYearMax, ariaHasPopup: xe = l.ariaHasPopup, autoFocus: g = l.autoFocus } = Q(te, t), d = () => w.current !== void 0 ? w.current : a.current && a.current.value, B = () => { const n = a.current && a.current.currentText || "", i = d(); return f != null && !Ae.focused && !i ? f : n; }, q = () => t.required !== void 0 ? t.required : !1, R = () => { const n = d() || t.value, i = me, b = fe, V = Ye(n, i, b) && Qe(n, ge, ve), k = H !== void 0, _ = (!q() || n != null) && V, Ve = t.valid !== void 0 ? t.valid : _; return { customError: k, rangeOverflow: n && b.getTime() < n.getTime() || !1, rangeUnderflow: n && n.getTime() < i.getTime() || !1, valid: Ve, valueMissing: n === null }; }, Ce = () => { o.current && o.current.focus(); }, z = () => new tt(ie), x = () => { const n = d(); return { format: P, steps: t.steps, formatPlaceholder: ce, placeholder: f, selectPreviousSegmentOnBackspace: !0, value: t.value || n, intlService: z(), autoFill: t.autoFill !== void 0 ? t.autoFill : !1, enableMouseWheel: be, autoCorrectParts: he, autoSwitchParts: Oe, autoSwitchKeys: t.autoSwitchKeys || [], twoDigitYearMax: Ie, allowCaretMode: Ee }; }, we = (n) => { s.current && s.current.classList.add("k-focus"), A({ focused: !0 }), g && J(!0); }, De = (n) => { s.current && s.current.classList.remove("k-focus"), A({ focused: !1 }); }, Te = (n, i) => typeof n != typeof i ? !0 : typeof n == "string" && typeof i == "string" ? n !== i : typeof n == "object" && typeof i == "object" ? JSON.stringify(n) !== JSON.stringify(i) : !1, Me = (n) => typeof n == "string" ? n : { inputFormat: n, displayFormat: n }, U = (n) => { w.current = d(), Ne(), m.current = n, w.current = void 0; }, W = (n) => { t.onChange && t.onChange(n); }, j = (n) => { ee(document) === o.current && n.preventDefault(); }, Se = () => new je(o.current, { ...x(), format: Me(x().format), events: { focus: we, blur: De, valueChange: U, click: W } }), K = () => { o.current && o.current.setCustomValidity && o.current.setCustomValidity( R().valid ? "" : H || l.validationMessage ); }, J = r.useCallback( (n) => { var i; if (o.current && g && n) { const b = (a == null ? void 0 : a.current).currentText, V = (a == null ? void 0 : a.current).currentText.search(/[^a-zA-Z]/), k = b[V], _ = b.split(k)[0].length; s.current && s.current.classList.add("k-focus"), (i = a == null ? void 0 : a.current) == null || i.selectNearestSegment(_); } }, [g] ), Pe = (n) => { !o.current || !a.current || U(n); }, Re = (n) => { n.preventDefault(); const i = ee(document); o.current && i !== o.current && o.current.focus({ preventScroll: !0 }); }, c = (n) => { const i = d(); m.current && t.onChange && !ke(m.current.oldValue, i) && t.onChange.call(void 0, { syntheticEvent: n, nativeEvent: m.current.event, value: m.current.value, target: C.current }), m.current = null; }, Le = (n) => { var i; (i = a.current) == null || i.modifyDateSegmentValue(1), c(n); }, pe = (n) => { var i; (i = a.current) == null || i.modifyDateSegmentValue(-1), c(n); }, C = r.useRef(null), o = r.useRef(null), s = r.useRef(null); r.useImperativeHandle( C, () => ({ props: t, get options() { return x(); }, get text() { return B(); }, get element() { return o.current; }, get name() { return t.name; }, get value() { return d(); }, get validity() { return R(); }, // hidden methods focus: Ce, updateOnPaste: Pe }) ), r.useImperativeHandle(re, () => C.current); const a = r.useRef(null), L = r.useRef(null), p = r.useRef(!1), w = r.useRef(null), m = r.useRef(null), v = r.useRef(t), [Ae, A] = r.useState({ focused: !1 }), [, Ne] = r.useReducer((n) => n + 1, 0); r.useLayoutEffect(() => { p.current || (a.current = Se(), L.current = a.current.dateObject, p.current = !0); }, []), r.useEffect(() => (K(), p.current || s.current && s.current.addEventListener("wheel", j, { passive: !1 }), g && (A({ focused: !0 }), J(!0)), () => { s.current && s.current.removeEventListener("wheel", j); }), []), r.useEffect(() => { K(), a.current && ((Te(v.current.format, P) || v.current.readonly !== t.readonly || JSON.stringify(v.current.steps) !== JSON.stringify(t.steps) || z().locale !== a.current.options.intlService.locale) && a.current.setOptions(x(), !0), v.current.value !== t.value && (L.current.getValue() !== null || t.value !== null) && L.current.setValue(t.value), t.ariaExpanded !== void 0 && t.ariaExpanded && (a.current.options.placeholder = null), t.ariaExpanded !== void 0 && !t.ariaExpanded && (a.current.options.placeholder = f), a.current.refreshElementValue(), v.current = { format: P, readonly: t.readonly, ariaExpanded: t.ariaExpanded, steps: t.steps, value: t.value }); }); const Y = t.id || ae + "-accessibility-id", y = F && F.uDateInput, X = B(), N = !ye || R().valid; r.useImperativeHandle(t._ref, () => C.current); const Z = /* @__PURE__ */ r.createElement( "span", { ref: (n) => { s.current = n; }, style: t.label ? void 0 : { width: t.width }, dir: t.dir, className: h( O.wrapper({ c: y, size: oe, fillMode: se, rounded: ue, disabled: I, required: q(), invalid: !N }), t.className ) }, /* @__PURE__ */ r.createElement( "input", { ref: (n) => { o.current = n; }, role: t.ariaRole || "textbox", readOnly: t.readonly, tabIndex: t.tabIndex || 0, disabled: I, title: t.title !== void 0 ? t.title : X, type: "text", spellCheck: !1, autoComplete: "off", autoCorrect: "off", autoFocus: g, className: h(O.inputInner({ c: y })), id: Y, value: X, "aria-label": t.ariaLabel, "aria-labelledby": t.ariaLabelledBy, "aria-describedby": t.ariaDescribedBy, "aria-haspopup": xe, "aria-disabled": I, "aria-expanded": t.ariaExpanded, "aria-controls": t.ariaControls, "aria-required": t.required, "aria-invalid": !N, onKeyDown: c, onChange: c, onWheel: c, onInput: c, onClick: c, name: t.name, ...t.inputAttributes } ), t.children, t.clearButton && t.value && /* @__PURE__ */ r.createElement(et, { onClick: W, key: "clearbutton" }), de && /* @__PURE__ */ r.createElement("span", { className: h(O.inputSpinner({ c: y })), onMouseDown: Re }, /* @__PURE__ */ r.createElement( $, { tabIndex: -1, type: "button", rounded: null, className: h(O.spinnerIncrease({ c: y })), icon: "caret-alt-up", svgIcon: _e, "aria-label": E.toLanguageString(T, M[T]), title: E.toLanguageString(T, M[T]), onClick: Le } ), /* @__PURE__ */ r.createElement( $, { tabIndex: -1, type: "button", rounded: null, className: h(O.spinnerDecrease({ c: y })), icon: "caret-alt-down", svgIcon: Fe, "aria-label": E.toLanguageString(S, M[S]), title: E.toLanguageString(S, M[S]), onClick: pe } )) ); return t.label ? /* @__PURE__ */ r.createElement( We, { label: t.label, editorId: Y, editorValue: (G = o.current) == null ? void 0 : G.value, editorValid: N, editorDisabled: I, children: Z, style: { width: t.width } } ) : Z; }); ne.propTypes = { value: e.instanceOf(Date), format: e.oneOfType([ u(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([ u( e.oneOf(["wide", "narrow", "short", "formatPattern"]) ), e.shape({ year: u(e.string), month: u(e.string), day: u(e.string), hour: u(e.string), minute: u(e.string), second: u(e.string) }) ]), width: e.oneOfType([e.string, e.number]), tabIndex: e.number, title: e.string, steps: e.shape({ year: u(e.number), month: u(e.number), day: u(e.number), hour: u(e.number), minute: u(e.number), second: u(e.number) }), min: e.instanceOf(Date), max: e.instanceOf(Date), disabled: e.bool, spinners: e.bool, name: e.string, dir: e.string, label: e.node, id: e.string, ariaLabelledBy: e.string, ariaDescribedBy: e.string, ariaLabel: e.string, ariaRole: e.string, ariaHasPopup: e.oneOfType([ e.bool, e.oneOf(["grid", "dialog"]) ]), ariaExpanded: e.oneOfType([e.bool]), onChange: e.func, validationMessage: e.string, required: 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"]), autoFocus: e.bool, inputAttributes: e.object }; const l = { format: Ke, size: "medium", rounded: "medium", fillMode: "solid", formatPlaceholder: Je, spinners: !1, disabled: !1, max: D(Xe), min: D(Ze), minTime: D(Ge), maxTime: D($e), validityStyles: !0, validationMessage: nt, placeholder: null, enableMouseWheel: !0, autoCorrectParts: !0, autoSwitchParts: !0, allowCaretMode: !1, twoDigitYearMax: 68, ariaHasPopup: "grid", autoFocus: !1 }, te = Ue(); ne.displayName = "KendoReactDateInput"; export { ne as DateInput, te as DateInputPropsContext, l as dateInputDefaultProps };