export const DECIMAL_INPUT_PATTERN = /^-?\d*([.,]\d*)?$/; export const normalizeDecimalInput = (value: string): string => { return value.replace(",", "."); }; export const trimToScale = (value: string, scale: number): string => { const normalized = normalizeDecimalInput(value); if (!normalized.includes(".")) { return normalized; } const [integerPart, decimalPart = ""] = normalized.split("."); return `${integerPart}.${decimalPart.slice(0, scale)}`; }; export const parseDecimalOrNull = (value: string): number | null => { const normalized = normalizeDecimalInput(value).trim(); if (normalized === "") { return null; } if (normalized === "-" || normalized === "." || normalized === "-.") { return null; } const parsed = Number(normalized); if (!Number.isFinite(parsed)) { return null; } return parsed; }; export const clampNumber = (value: number, min?: number, max?: number): number => { if (typeof min === "number" && value < min) { return min; } if (typeof max === "number" && value > max) { return max; } return value; }; export const formatDecimalValue = (value: number | null | undefined, scale: number): string => { if (value === null || value === undefined || Number.isNaN(value)) { return ""; } const asString = String(value); if (!asString.includes(".")) { return asString; } const [integerPart, decimalPart = ""] = asString.split("."); const trimmedDecimalPart = decimalPart.slice(0, scale).replace(/0+$/, ""); return trimmedDecimalPart.length > 0 ? `${integerPart}.${trimmedDecimalPart}` : `${integerPart}`; };