@chayns-components/core
Version:
A set of beautiful React components for developing your own applications with chayns.
153 lines (149 loc) • 6.54 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = _interopRequireWildcard(require("react"));
var _numberInput = require("../../constants/numberInput");
var _numberInput2 = require("../../utils/numberInput");
var _Input = _interopRequireDefault(require("../input/Input"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
const NumberInput = ({
isDecimalInput,
isMoneyInput,
isTimeInput,
isInvalid,
maxNumber = Infinity,
value,
shouldTriggerChangeOnFormat = true,
placeholder,
onBlur,
isDisabled,
onChange,
shouldShowOnlyBottomBorder,
minNumber = -Infinity
}) => {
// the plainText will be shown in the input, when it is in focus
const [plainText, setPlainText] = (0, _react.useState)('');
// the formattedValue will be shown in the input, when it is not in focus
const [formattedValue, setFormattedValue] = (0, _react.useState)('');
const [hasFocus, setHasFocus] = (0, _react.useState)(false);
const [shouldRemainPlaceholder, setShouldRemainPlaceholder] = (0, _react.useState)(false);
const [isValueInvalid, setIsValueInvalid] = (0, _react.useState)(false);
const localPlaceholder = placeholder ?? (isMoneyInput ? '€' : undefined);
const onLocalChange = event => {
const newValue = event.target.value;
const sanitizedValueString = newValue
// Removes everything except numbers, commas and points
.replace(_numberInput.NUMBER_CLEAR_REGEX, '');
if (isTimeInput && (sanitizedValueString.includes(':') && sanitizedValueString.length > 5 || !sanitizedValueString.includes(':') && sanitizedValueString.length > 4)) {
return;
}
const valueToCheck = sanitizedValueString.replaceAll(',', '.');
if (!(0, _numberInput2.isValidString)({
string: valueToCheck,
isMoneyInput,
isDecimalInput,
isTimeInput
})) {
return;
}
if (maxNumber && Number(valueToCheck) > maxNumber || minNumber && Number(valueToCheck) < minNumber) {
return;
}
if (newValue.length === 1 && newValue.match(/^[0-9]+$/) === null) {
setShouldRemainPlaceholder(true);
} else {
setShouldRemainPlaceholder(false);
}
setPlainText(sanitizedValueString.replaceAll('.', ','));
if (typeof onChange === 'function') {
onChange(sanitizedValueString.replaceAll('.', ','));
}
};
const onLocalBlur = () => {
const sanitizedValue = plainText.length === 0 ? '0' : plainText;
let newIsInvalid = false;
let parsedNumber = null;
if (!isTimeInput) {
parsedNumber = (0, _numberInput2.parseFloatWithDecimals)({
stringValue: sanitizedValue.replace(',', '.').replaceAll(':', '').replace('€', ''),
decimals: isMoneyInput ? 2 : undefined
});
if (parsedNumber !== 0 && (parsedNumber > maxNumber || parsedNumber < minNumber)) {
newIsInvalid = true;
}
setIsValueInvalid(newIsInvalid);
}
const newStringValue = plainText.length === 0 ? '' : (0, _numberInput2.formateNumber)({
number: isTimeInput ? sanitizedValue : parsedNumber,
isMoneyInput,
isTimeInput
});
setFormattedValue(`${newStringValue} ${isMoneyInput ? '€' : ''}`);
setPlainText(newStringValue.replaceAll('.', ''));
setHasFocus(false);
if (typeof onChange === 'function' && shouldTriggerChangeOnFormat) {
onChange(newStringValue.replaceAll('.', ''));
}
if (typeof onBlur === 'function') {
if (isTimeInput) {
onBlur(newStringValue, newIsInvalid);
} else {
onBlur(parsedNumber === 0 ? null : parsedNumber, newIsInvalid);
}
}
};
const onLocalFocus = () => {
// formattedValue will be a number string with german number format (e.g. 1.000,00)
// It will remove all dots, so that the user can type in the number
setPlainText(formattedValue.replaceAll('.', '').replace('€', '').replaceAll(' ', ''));
// This will update the external state
if (typeof onChange === 'function' && shouldTriggerChangeOnFormat) {
onChange(formattedValue.replaceAll('.', '').replace('€', '').replaceAll(' ', ''));
}
setIsValueInvalid(false);
setHasFocus(true);
};
// updates the formattedValue, when the value changes
(0, _react.useEffect)(() => {
let parsedNumber = null;
if (!isTimeInput) {
parsedNumber = (0, _numberInput2.parseFloatWithDecimals)({
stringValue: plainText.replace(',', '.').replaceAll(':', '').replace('€', '').replaceAll(' ', ''),
decimals: isMoneyInput ? 2 : undefined
});
// checks, if a given number is invalid, if the input is not in focus
if (!hasFocus) {
setIsValueInvalid(parsedNumber > maxNumber || parsedNumber < minNumber);
}
}
setFormattedValue(plainText.length === 0 ? '' : `${(0, _numberInput2.formateNumber)({
number: isTimeInput ? plainText : parsedNumber,
isMoneyInput,
isTimeInput
})}${isMoneyInput ? ' €' : ''}`);
}, [hasFocus, isMoneyInput, isTimeInput, maxNumber, minNumber, plainText]);
(0, _react.useEffect)(() => {
if (typeof value === 'string') {
setPlainText(value.replace('€', '').replaceAll(' ', ''));
}
}, [value]);
return /*#__PURE__*/_react.default.createElement(_Input.default, {
shouldRemainPlaceholder: shouldRemainPlaceholder,
shouldShowOnlyBottomBorder: shouldShowOnlyBottomBorder,
inputMode: "decimal",
onChange: onLocalChange,
value: hasFocus ? plainText : formattedValue,
placeholder: localPlaceholder,
onBlur: onLocalBlur,
onFocus: onLocalFocus,
isDisabled: isDisabled,
isInvalid: typeof isInvalid === 'boolean' ? isInvalid : isValueInvalid,
shouldShowCenteredContent: shouldShowOnlyBottomBorder
});
};
NumberInput.displayName = 'NumberInput';
var _default = exports.default = NumberInput;
//# sourceMappingURL=NumberInput.js.map