@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
177 lines (176 loc) • 6.15 kB
JavaScript
;
"use client";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = require("react");
var _Context = _interopRequireDefault(require("../../shared/Context.js"));
var _componentHelper = require("../../shared/component-helper.js");
var _index = require("./utils/index.js");
var _compact = require("./utils/compact.js");
var _formatCore = require("./utils/formatCore.js");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function useNumberFormatWithParts(value, formatter = _index.formatNumber, options = {}) {
var _params$compact, _parseFormatParts;
const context = (0, _react.useContext)(_Context.default);
const params = (0, _componentHelper.extendPropsWithContext)({
returnAria: true,
...options
}, {
locale: context.locale
}, context.NumberFormat);
const result = formatter(value, params);
if (typeof result === 'string') {
return result;
}
const compactValue = params.clean ? (0, _index.cleanNumber)(value) : value;
const compact = (0, _compact.canHandleCompact)({
value: compactValue !== null && compactValue !== void 0 ? compactValue : '',
compact: (_params$compact = params.compact) !== null && _params$compact !== void 0 ? _params$compact : null
});
const formatParts = (0, _formatCore.getReturnValueParts)(result);
return {
...result,
parts: (_parseFormatParts = parseFormatParts(formatParts, result.type)) !== null && _parseFormatParts !== void 0 ? _parseFormatParts : parseParts(result.number, result.type, compact)
};
}
const SIGN_RE = /^[\u200e\u200f\u061c\s]*([+\-\u2212])?\s*/;
const NUMBER_RE = /[0-9](?:[0-9.,]|[\s\u00A0\u202F](?=[0-9]))*/;
const PERCENT_RE = /^([\u00A0\u202F\s]*)([%٪])\s*$/;
const NUMBER_PART_TYPES = new Set(['integer', 'group', 'decimal', 'fraction', 'compact', 'nan', 'infinity']);
const SIGN_PART_TYPES = new Set(['minusSign', 'plusSign']);
function isSpacingLiteral(value) {
return value.trim() === '';
}
function parseFormatParts(parts, type = 'number') {
if (!parts?.length) {
return null;
}
let sign = null;
let number = '';
let currencyBefore = '';
let currencyAfter = '';
let spacingBeforeNumber = '';
let spacingAfterNumber = '';
let percent = '';
let percentSpacing = '';
let hasNumber = false;
parts.forEach((part, index) => {
if (SIGN_PART_TYPES.has(part.type)) {
sign = part.value;
return;
}
if (NUMBER_PART_TYPES.has(part.type)) {
hasNumber = true;
number += part.value;
return;
}
if (part.type === 'currency') {
if (hasNumber) {
currencyAfter += part.value;
} else {
currencyBefore += part.value;
}
return;
}
if (part.type === 'percentSign') {
percent += part.value;
return;
}
if (part.type === 'literal') {
if (percent) {
return;
}
if (hasNumber && parts[index + 1]?.type === 'compact') {
number += part.value;
return;
}
if (!isSpacingLiteral(part.value)) {
return;
}
if (hasNumber) {
spacingAfterNumber += part.value;
} else {
spacingBeforeNumber += part.value;
}
}
});
if (!hasNumber) {
return null;
}
const currency = type === 'currency' ? currencyBefore || currencyAfter || null : null;
if (percent) {
const percentIndex = parts.findIndex(({
type
}) => type === 'percentSign');
const previousPart = parts[percentIndex - 1];
if (previousPart?.type === 'literal') {
percentSpacing = previousPart.value;
}
}
return {
sign,
signedNumber: sign ? `${sign}${number}` : number,
number,
currency,
currencyPosition: currencyBefore ? 'before' : currencyAfter ? 'after' : null,
spaceAfterCurrency: Boolean(currencyBefore && spacingBeforeNumber),
spaceBeforeCurrency: Boolean(currencyAfter && spacingAfterNumber),
percent: percent || null,
percentSpacing
};
}
function parseParts(input, type = 'number', compact = false) {
var _signMatch$, _numberMatch$index;
const source = String(input !== null && input !== void 0 ? input : '');
const signMatch = source.match(SIGN_RE);
const sign = (_signMatch$ = signMatch[1]) !== null && _signMatch$ !== void 0 ? _signMatch$ : null;
const afterSign = source.slice(signMatch[0].length);
const numberMatch = afterSign.match(NUMBER_RE);
if (!numberMatch) {
return {
sign,
signedNumber: source.trim(),
number: afterSign.trim(),
currency: null,
currencyPosition: null,
spaceAfterCurrency: false,
spaceBeforeCurrency: false,
percent: null,
percentSpacing: ''
};
}
let number = numberMatch[0].trim();
const numberIndex = (_numberMatch$index = numberMatch.index) !== null && _numberMatch$index !== void 0 ? _numberMatch$index : 0;
const before = afterSign.slice(0, numberIndex).trim();
let after = afterSign.slice(numberIndex + numberMatch[0].length);
if (compact && !PERCENT_RE.test(after)) {
const compactMatch = after.match(/^([\s\u00A0\u202F]*[^\d\s\u00A0\u202F]+)/);
if (compactMatch) {
number += compactMatch[1];
after = after.slice(compactMatch[1].length);
}
}
const signedNumber = sign ? `${sign}${number}` : number;
const percentMatch = after.match(PERCENT_RE);
const percent = percentMatch ? percentMatch[2] : null;
const percentSpacing = percentMatch ? percentMatch[1] : '';
const trailing = percentMatch ? '' : after.trim();
const hasBefore = before.length > 0;
const hasAfter = trailing.length > 0;
const currency = type === 'currency' ? hasBefore ? before : hasAfter ? trailing : null : null;
return {
sign,
signedNumber,
number,
currency,
currencyPosition: type === 'currency' ? hasBefore ? 'before' : hasAfter ? 'after' : null : null,
spaceAfterCurrency: type === 'currency' && hasBefore,
spaceBeforeCurrency: type === 'currency' && hasAfter,
percent,
percentSpacing
};
}
var _default = exports.default = useNumberFormatWithParts;
//# sourceMappingURL=useNumberFormatWithParts.js.map