@progress/kendo-react-inputs
Version:
React Inputs offer a customizable interface for users to enter and pick different information. KendoReact Input package
410 lines (409 loc) • 12.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 t from "prop-types";
import { useInternationalization as Xe, useLocalization as Ze } from "@progress/kendo-react-intl";
import { createPropsContext as et, usePropsContext as tt, useId as nt, useCustomComponent as pe, dispatchEvent as Q, getActiveElement as be, useIsomorphicLayoutEffect as rt, classNames as at, kendoThemeMaps as ge, getTabIndex as lt } from "@progress/kendo-react-common";
import { caretAltUpIcon as st, caretAltDownIcon as ut } from "@progress/kendo-svg-icons";
import { FloatingLabel as ot } from "@progress/kendo-react-labels";
import { numericIncreaseValue as M, messages as T, numericDecreaseValue as z } from "../messages/index.mjs";
import { getInitialState as ve, formatValue as q, getStateOrPropsValue as X, rangeValue as A, sanitizeNumber as ye, decreaseValue as Ve, increaseValue as ke } from "./utils/index.mjs";
import { Button as Ce } from "@progress/kendo-react-buttons";
const it = "Please enter a valid value!", ct = et(), Ee = n.forwardRef(
(C, Se) => {
const G = tt(
ct,
C
), {
className: xe,
value: g,
defaultValue: he,
format: l,
width: Z,
tabIndex: Ie,
accessKey: Oe,
title: Le,
placeholder: ee,
min: c,
max: d,
dir: te,
name: j,
label: I,
id: Pe,
ariaDescribedBy: Ne,
ariaLabelledBy: De,
ariaLabel: Re,
inputType: Fe,
readOnly: f,
validationMessage: _,
children: Be,
// Removed to support direct use in Form Field component
touched: dt,
visited: mt,
modified: ft,
style: ne,
inputStyle: Me,
valid: H,
step: v = o.step,
spinners: Te = o.spinners,
disabled: u = o.disabled,
required: O = o.required,
validityStyles: re = o.validityStyles,
prefix: ze = o.prefix,
suffix: qe = o.suffix,
onChange: E = o.onChange,
onFocus: ae = o.onFocus,
onBlur: le = o.onBlur,
rangeOnEnter: se = o.rangeOnEnter,
size: K = o.size,
rounded: w = o.rounded,
fillMode: L = o.fillMode,
autoFocus: Ae = o.autoFocus,
inputAttributes: Ge,
...ue
} = G, je = nt(), oe = Pe || je, s = Xe(), P = Ze(), a = n.useRef(null), N = n.useRef(void 0), [_e, S] = n.useState(!1), i = n.useRef(ve()), D = n.useRef(!1), U = n.useRef(void 0), x = n.useRef(he), h = q(
i.current.focused && !u ? i.current.currentLooseValue : X(g, x.current),
l,
s
);
U.current = h;
const [He] = pe(ze), [Ke] = pe(qe);
n.useEffect(() => {
a.current && a.current.setCustomValidity && a.current.setCustomValidity(
B().valid ? "" : _ || it
);
});
const ie = n.useCallback(() => {
a.current && a.current.focus();
}, []), R = n.useCallback(() => N.current !== void 0 ? N.current : X(g, x.current), [g]), ce = n.useCallback(() => j, [j]), F = n.useCallback(() => O, [O]), B = n.useCallback(() => {
const r = _ !== void 0, e = R(), V = H !== void 0 ? H : !i.current.valueIsOutOfRange && (!F() || e != null);
return {
customError: r,
valid: V,
valueMissing: e == null
};
}, [_, H, R, F]), $ = n.useCallback(() => re, [re]), de = n.useCallback(() => G, [G]), y = n.useCallback(() => {
const r = {
element: a.current,
focus: ie
};
return Object.defineProperty(r, "name", { get: ce }), Object.defineProperty(r, "value", { get: R }), Object.defineProperty(r, "validity", { get: B }), Object.defineProperty(r, "validityStyles", { get: $ }), Object.defineProperty(r, "required", { get: F }), Object.defineProperty(r, "props", { get: de }), r;
}, [ce, R, B, $, F, ie, de]);
n.useImperativeHandle(Se, y);
const p = n.useCallback(() => ({
eventValue: X(g, x.current),
prevLooseValue: U.current,
currentLooseValue: a.current.value,
selectionStart: a.current.selectionStart,
selectionEnd: a.current.selectionEnd,
decimalSelect: !1,
valueIsCorrected: !1,
valueIsOutOfRange: !1,
isPaste: D.current,
focused: i.current.focused
}), [g]), b = n.useCallback(
(r, e) => {
if (u)
return;
N.current = e.eventValue, x.current = e.eventValue;
const V = q(A(e.eventValue, c, d), l, s), m = A(s.parseNumber(V, l), c, d);
m !== e.eventValue && (e.valueIsOutOfRange = !0, e.eventValue = m, x.current = m), g !== e.eventValue && Q(E, r, y(), {
value: e.eventValue
}), N.current = void 0, i.current = e, S((J) => !J);
},
[g, E, u, S, y]
), we = n.useCallback(
(r) => {
const e = p();
D.current = !1, b(r, ye(e, l, s));
},
[l, E, s, b, p]
), Ue = n.useCallback(
(r) => {
if (f || u)
return;
let e = p();
const V = s.parseNumber(String(e.currentLooseValue), l);
if (e.selectionEnd > e.selectionStart && e.selectionEnd - e.selectionStart === String(e.currentLooseValue).length) {
const m = s.numberSymbols(), k = m && r.key === m.minusSign, J = m && r.key === m.decimal;
D.current = !k && !J;
return;
}
switch (r.keyCode) {
case 38:
ke(V, e, v, c, d, l, s);
break;
case 40:
Ve(V, e, v, c, d, l, s);
break;
case 13: {
if (se === !1)
return;
const m = q(A(V, c, d), l, s), k = A(s.parseNumber(m, l), c, d);
e.eventValue = k, e.currentLooseValue = q(k, l, s), e.selectionStart = e.selectionEnd = e.currentLooseValue.length;
break;
}
case 110: {
const m = a.current, k = s.numberSymbols();
m && (e.currentLooseValue = e.currentLooseValue.slice(0, e.selectionStart) + k.decimal + e.currentLooseValue.slice(e.selectionEnd), e.selectionStart = e.selectionEnd = e.selectionStart + 1, e = ye(e, l, s));
break;
}
default:
return;
}
r.preventDefault(), b(r, e);
},
[l, c, d, v, E, se, b, p]
), $e = n.useCallback(() => {
D.current = !0;
}, []), W = n.useCallback(
(r) => {
if (f || u)
return;
const e = p();
ke(
s.parseNumber(String(e.currentLooseValue), l),
e,
v,
c,
d,
l,
s
), b(r, e);
},
[l, c, d, v, E, f, u, b, p]
), Y = n.useCallback(
(r) => {
if (f || u)
return;
const e = p();
Ve(
s.parseNumber(String(e.currentLooseValue), l),
e,
v,
c,
d,
l,
s
), b(r, e);
},
[l, c, d, v, E, f, u, b, p]
), We = n.useCallback(
(r) => {
const e = be(document);
!document || e !== a.current || !a.current || f || u || (r.nativeEvent.deltaY < 0 && W(r), r.nativeEvent.deltaY > 0 && Y(r));
},
[W, Y, u, f]
), Ye = n.useCallback(
(r) => {
i.current.currentLooseValue = U.current, i.current.focused = !0, Q(ae, r, y(), {}), S((e) => !e);
},
[ae, S, y]
), Je = n.useCallback(
(r) => {
i.current = ve(), Q(le, r, y(), {}), S((e) => !e);
},
[le, S, y]
), Qe = n.useCallback((r) => {
if (document && a.current) {
const e = be(document);
r.preventDefault(), e !== a.current && a.current.focus();
}
}, []);
rt(() => {
a.current && a.current.type !== "number" && i.current.selectionStart !== void 0 && i.current.selectionEnd !== void 0 && (a.current.selectionStart = i.current.selectionStart, a.current.selectionEnd = i.current.selectionEnd, i.current.selectionStart = void 0, i.current.selectionEnd = void 0);
}, [_e]);
const me = !$() || B().valid, fe = /* @__PURE__ */ n.createElement(
"span",
{
dir: te,
style: I ? ne : { width: Z, ...ne },
className: at(
"k-input",
"k-numerictextbox",
{
[`k-input-${ge.sizeMap[K] || K}`]: K,
[`k-input-${L}`]: L,
[`k-rounded-${ge.roundedMap[w] || w}`]: w,
"k-invalid": !me,
"k-required": O,
"k-disabled": u
},
xe
),
"aria-disabled": u ? "true" : void 0,
...I ? {} : ue
},
/* @__PURE__ */ n.createElement(He, null),
/* @__PURE__ */ n.createElement(
"input",
{
role: "spinbutton",
value: h === null ? "" : h,
tabIndex: lt(Ie, u),
accessKey: Oe,
disabled: u,
title: Le,
"aria-disabled": u ? "true" : void 0,
"aria-valuemin": c,
"aria-valuemax": d,
"aria-label": Re,
"aria-labelledby": De,
"aria-describedby": Ne,
"aria-required": O,
placeholder: ee,
spellCheck: !1,
autoComplete: "off",
autoCorrect: "off",
autoFocus: Ae,
type: Fe || "tel",
className: "k-input-inner",
id: oe,
name: j,
readOnly: f,
style: Me,
onChange: we,
onFocus: Ye,
onBlur: Je,
onKeyDown: Ue,
onPaste: $e,
onWheel: We,
ref: a,
...Ge
}
),
/* @__PURE__ */ n.createElement(Ke, null),
Be,
Te && /* @__PURE__ */ n.createElement("span", { className: "k-input-spinner k-spin-button", onMouseDown: Qe }, /* @__PURE__ */ n.createElement(
Ce,
{
tabIndex: -1,
type: "button",
icon: "caret-alt-up",
svgIcon: st,
rounded: null,
fillMode: L,
className: "k-spinner-increase",
"aria-label": P.toLanguageString(
M,
T[M]
),
title: P.toLanguageString(
M,
T[M]
),
onClick: W
}
), /* @__PURE__ */ n.createElement(
Ce,
{
tabIndex: -1,
type: "button",
icon: "caret-alt-down",
svgIcon: ut,
rounded: null,
fillMode: L,
className: "k-spinner-decrease",
"aria-label": P.toLanguageString(
z,
T[z]
),
title: P.toLanguageString(
z,
T[z]
),
onClick: Y
}
))
);
return I ? /* @__PURE__ */ n.createElement(
ot,
{
label: I,
editorId: oe,
editorValue: h === null ? "" : h,
editorValid: me,
editorDisabled: u,
editorPlaceholder: ee,
children: fe,
style: { width: Z },
dir: te,
...ue
}
) : fe;
}
);
Ee.propTypes = {
value: t.number,
defaultValue: t.number,
step: t.number,
format: t.oneOfType([
t.string,
t.shape({
style: t.oneOf(["decimal", "currency", "percent", "scientific", "accounting"]),
currency: t.string,
currencyDisplay: t.oneOf(["symbol", "code", "name"]),
useGrouping: t.bool,
minimumIntegerDigits: t.number,
minimumFractionDigits: t.number,
maximumFractionDigits: t.number
})
]),
width: t.oneOfType([t.string, t.number]),
tabIndex: t.number,
accessKey: t.string,
title: t.string,
placeholder: t.string,
min: t.number,
max: t.number,
spinners: t.bool,
disabled: t.bool,
readOnly: t.bool,
dir: t.string,
name: t.string,
label: t.string,
validationMessage: t.string,
required: t.bool,
id: t.string,
rangeOnEnter: t.bool,
ariaLabelledBy: t.string,
ariaDescribedBy: t.string,
ariaLabel: t.string,
onChange: t.func,
onFocus: t.func,
onBlur: t.func,
size: t.oneOf([null, "small", "medium", "large"]),
rounded: t.oneOf([null, "small", "medium", "large", "full"]),
fillMode: t.oneOf([null, "solid", "flat", "outline"]),
inputAttributes: t.object
};
const o = {
prefix: (C) => null,
suffix: (C) => null,
step: 1,
spinners: !0,
disabled: !1,
required: !1,
validityStyles: !0,
rangeOnEnter: !0,
autoFocus: !1,
onChange: (C) => {
},
onFocus: (C) => {
},
onBlur: (C) => {
},
size: "medium",
rounded: "medium",
fillMode: "solid"
};
Ee.displayName = "KendoNumericTextBox";
export {
Ee as NumericTextBox,
ct as NumericTextBoxPropsContext
};