vueless
Version:
Vue Styleless UI Component Library, powered by Tailwind CSS.
64 lines (44 loc) • 2.19 kB
text/typescript
import { RAW_DECIMAL_MARK } from "./constants";
import type { FormatOptions } from "./types";
export function getFixedNumber(value: number, maxDecimals: number = 10): number | "" {
if (!isFinite(value) || isNaN(value)) return "";
if (maxDecimals < 0) maxDecimals = 10;
return parseFloat(value.toFixed(maxDecimals));
}
export function getRawValue(
value: string,
options: Pick<FormatOptions, "prefix" | "decimalSeparator" | "thousandsSeparator">,
): Intl.StringNumericLiteral {
const { thousandsSeparator, decimalSeparator, prefix } = options;
value = value.endsWith(decimalSeparator) ? value.replace(decimalSeparator, "") : value;
const rawValueWithPrefix = value
.replaceAll(thousandsSeparator, "")
.replace(decimalSeparator, RAW_DECIMAL_MARK);
return rawValueWithPrefix.replace(prefix, "") as Intl.StringNumericLiteral;
}
export function getFormattedValue(value: string, options: FormatOptions): string {
const { thousandsSeparator, decimalSeparator, prefix, positiveOnly } = options;
const minFractionDigits = Math.abs(options.minFractionDigits);
const maxFractionDigits = Math.abs(options.maxFractionDigits);
const isValidMinFractionDigits = minFractionDigits <= maxFractionDigits;
const actualMinFractionDigit = isValidMinFractionDigits ? minFractionDigits : maxFractionDigits;
const numericValue = parseFloat(value);
const fixedValue = getFixedNumber(numericValue, Math.max(maxFractionDigits, 10));
if (fixedValue === "") return prefix;
const intlNumberOptions: Intl.NumberFormatOptions = {
minimumFractionDigits: actualMinFractionDigit,
maximumFractionDigits: maxFractionDigits,
roundingMode: "trunc",
};
if (positiveOnly) {
intlNumberOptions.signDisplay = "never";
}
const intlNumber = new Intl.NumberFormat("en-US", intlNumberOptions);
const formattedValue = intlNumber.formatToParts(fixedValue).map((part) => {
if (part.type === "group") part.value = thousandsSeparator;
if (part.type === "decimal") part.value = decimalSeparator;
return part;
});
formattedValue.unshift({ value: prefix, type: "minusSign" });
return formattedValue.map((part) => part.value).join("");
}