UNPKG

@itwin/presentation-components

Version:

React components based on iTwin.js Presentation library

113 lines 5.52 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.NumericInput = exports.NumericPropertyInput = void 0; const jsx_runtime_1 = require("react/jsx-runtime"); /*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ const react_1 = require("react"); const appui_abstract_1 = require("@itwin/appui-abstract"); const itwinui_react_1 = require("@itwin/itwinui-react"); const Utils_js_1 = require("./Utils.js"); /** @internal */ exports.NumericPropertyInput = (0, react_1.forwardRef)((props, ref) => { const { onCommit, propertyRecord, setFocus } = props; const property = propertyRecord.property; const [inputValue, setInputValue] = (0, react_1.useState)(() => getInputTargetFromPropertyRecord(propertyRecord) ?? ""); const handleChange = (newVal) => { setInputValue(newVal); }; const { min, max } = property.constraints ? getMinMaxFromPropertyConstraints(property.constraints) : { min: undefined, max: undefined }; const commitInput = () => { const formattedInputValue = applyConstraints(inputValue, min, max); setInputValue(formattedInputValue); onCommit && onCommit({ propertyRecord, newValue: parsePrimitiveValue(formattedInputValue), }); }; return ((0, jsx_runtime_1.jsx)(exports.NumericInput, { onChange: handleChange, value: inputValue, onBlur: commitInput, isDisabled: propertyRecord.isReadonly, setFocus: setFocus, ref: ref, min: min, max: max })); }); exports.NumericPropertyInput.displayName = "NumericPropertyInput"; function parsePrimitiveValue(value) { const isValid = value && !isNaN(Number(value)); return { valueFormat: appui_abstract_1.PropertyValueFormat.Primitive, value: isValid ? Number(value) : undefined, displayValue: value, roundingError: isValid ? (0, Utils_js_1.getDecimalRoundingError)(value) : undefined, }; } function getInputTargetFromPropertyRecord(propertyRecord) { const value = propertyRecord.value; /* c8 ignore next 3 */ if (value.valueFormat !== appui_abstract_1.PropertyValueFormat.Primitive) { return undefined; } // eslint-disable-next-line @typescript-eslint/no-base-to-string return value.value?.toString(); } /** @internal */ exports.NumericInput = (0, react_1.forwardRef)(({ value, onChange, onBlur, isDisabled, setFocus, min, max }, ref) => { const inputRef = (0, react_1.useRef)(null); (0, react_1.useImperativeHandle)(ref, () => ({ getValue: () => parsePrimitiveValue(value), htmlElement: inputRef.current, }), [value]); const handleChange = (e) => { const val = e.currentTarget.value; // Check if it is a correct number and it is not infinity. if (!isNaN(Number(val)) && isFinite(Number(val))) { onChange(val); } // Number{"+"), Number("-") and Number(".") returns NaN, but if input is only `.`, `-` or `+`, we should fire `onChange` function. else if (val.length === 1 && "+-.".includes(val)) { onChange(val); } // Number("+.") and Number("-.") returns NaN, but if input is only `+.` or `-.`, we want to fire `onChange` function. else if (val === "+." || val === "-.") { onChange(val); } // Let user write scientific numbers. Number("1e") returns NaN, but we want to fire `onChange` function when input before `e` is a correct number. else if (val.endsWith("e") && !isNaN(Number(val.slice(0, val.length - 1))) && val.length !== 1) { onChange(val); } // Let user write scientific numbers. Number("1e-") returns NaN, but we want to fire `onChange` function when input before `e-` is a correct number. // We don't need to check if string before `e-` is a valid number, because there is a check if string before `e` is a correct number. else if (val.endsWith("e-")) { onChange(val); } }; (0, react_1.useEffect)(() => { if (setFocus) { inputRef.current && inputRef.current.focus(); } }, [setFocus]); return ((0, jsx_runtime_1.jsx)(itwinui_react_1.Input, { ref: inputRef, disabled: isDisabled, "data-testid": "numeric-input", size: "small", value: value, min: min, max: max, onChange: handleChange, onBlur: onBlur, onFocus: () => inputRef.current?.setSelectionRange(0, 9999) })); }); exports.NumericInput.displayName = "NumericInput"; function applyConstraints(inputAsNumber, min, max) { if (min === undefined && max === undefined) { return inputAsNumber; } if (!isFinite(Number(inputAsNumber))) { return inputAsNumber; } let valAsNumber = Number(inputAsNumber); if (min !== undefined) { valAsNumber = Math.max(valAsNumber, min); } if (max !== undefined) { valAsNumber = Math.min(valAsNumber, max); } return valAsNumber.toString(); } function getMinMaxFromPropertyConstraints(constraints) { if ("minimumValue" in constraints) { return { min: constraints.minimumValue, max: constraints.maximumValue }; } return { min: undefined, max: undefined }; } //# sourceMappingURL=NumericPropertyInput.js.map