@internationalized/number 3.6.6 → 3.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -48,7 +48,10 @@ class $7fe67f77592add0a$export$cc77c4ff7e8673c5 {
48
48
  this.numberFormatter = $7fe67f77592add0a$var$getCachedNumberFormatter(locale, options);
49
49
  this.options = options;
50
50
  }
51
- /** Formats a number value as a string, according to the locale and options provided to the constructor. */ format(value) {
51
+ /**
52
+ * Formats a number value as a string, according to the locale and options provided to the
53
+ * constructor.
54
+ */ format(value) {
52
55
  let res = '';
53
56
  if (!$7fe67f77592add0a$var$supportsSignDisplay && this.options.signDisplay != null) res = $7fe67f77592add0a$export$711b50b3c525e0f2(this.numberFormatter, this.options.signDisplay, value);
54
57
  else res = this.numberFormatter.format(value);
@@ -1 +1 @@
1
- {"mappings":"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","sources":["packages/@internationalized/number/src/NumberFormatter.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nlet formatterCache = new Map<string, Intl.NumberFormat>();\n\nlet supportsSignDisplay = false;\ntry {\n supportsSignDisplay = (new Intl.NumberFormat('de-DE', {signDisplay: 'exceptZero'})).resolvedOptions().signDisplay === 'exceptZero';\n // eslint-disable-next-line no-empty\n} catch {}\n\nlet supportsUnit = false;\ntry {\n supportsUnit = (new Intl.NumberFormat('de-DE', {style: 'unit', unit: 'degree'})).resolvedOptions().style === 'unit';\n // eslint-disable-next-line no-empty\n} catch {}\n\n// Polyfill for units since Safari doesn't support them yet. See https://bugs.webkit.org/show_bug.cgi?id=215438.\n// Currently only polyfilling the unit degree in narrow format for ColorSlider in our supported locales.\n// Values were determined by switching to each locale manually in Chrome.\nconst UNITS = {\n degree: {\n narrow: {\n default: '°',\n 'ja-JP': ' 度',\n 'zh-TW': '度',\n 'sl-SI': ' °'\n // Arabic?? But Safari already doesn't use Arabic digits so might be ok...\n // https://bugs.webkit.org/show_bug.cgi?id=218139\n }\n }\n};\n\nexport interface NumberFormatOptions extends Intl.NumberFormatOptions {\n /** Overrides default numbering system for the current locale. */\n numberingSystem?: string\n}\n\ninterface NumberRangeFormatPart extends Intl.NumberFormatPart {\n source: 'startRange' | 'endRange' | 'shared'\n}\n\n/**\n * A wrapper around Intl.NumberFormat providing additional options, polyfills, and caching for performance.\n */\nexport class NumberFormatter implements Intl.NumberFormat {\n private numberFormatter: Intl.NumberFormat;\n private options: NumberFormatOptions;\n\n constructor(locale: string, options: NumberFormatOptions = {}) {\n this.numberFormatter = getCachedNumberFormatter(locale, options);\n this.options = options;\n }\n\n /** Formats a number value as a string, according to the locale and options provided to the constructor. */\n format(value: number): string {\n let res = '';\n if (!supportsSignDisplay && this.options.signDisplay != null) {\n res = numberFormatSignDisplayPolyfill(this.numberFormatter, this.options.signDisplay, value);\n } else {\n res = this.numberFormatter.format(value);\n }\n\n if (this.options.style === 'unit' && !supportsUnit) {\n let {unit, unitDisplay = 'short', locale} = this.resolvedOptions();\n if (!unit) {\n return res;\n }\n let values = UNITS[unit]?.[unitDisplay];\n res += values[locale] || values.default;\n }\n\n return res;\n }\n\n /** Formats a number to an array of parts such as separators, digits, punctuation, and more. */\n formatToParts(value: number): Intl.NumberFormatPart[] {\n // TODO: implement signDisplay for formatToParts\n return this.numberFormatter.formatToParts(value);\n }\n\n /** Formats a number range as a string. */\n formatRange(start: number, end: number): string {\n if (typeof this.numberFormatter.formatRange === 'function') {\n return this.numberFormatter.formatRange(start, end);\n }\n\n if (end < start) {\n throw new RangeError('End date must be >= start date');\n }\n\n // Very basic fallback for old browsers.\n return `${this.format(start)} – ${this.format(end)}`;\n }\n\n /** Formats a number range as an array of parts. */\n formatRangeToParts(start: number, end: number): NumberRangeFormatPart[] {\n if (typeof this.numberFormatter.formatRangeToParts === 'function') {\n return this.numberFormatter.formatRangeToParts(start, end);\n }\n\n if (end < start) {\n throw new RangeError('End date must be >= start date');\n }\n\n let startParts = this.numberFormatter.formatToParts(start);\n let endParts = this.numberFormatter.formatToParts(end);\n return [\n ...startParts.map(p => ({...p, source: 'startRange'} as NumberRangeFormatPart)),\n {type: 'literal', value: ' – ', source: 'shared'},\n ...endParts.map(p => ({...p, source: 'endRange'} as NumberRangeFormatPart))\n ];\n }\n\n /** Returns the resolved formatting options based on the values passed to the constructor. */\n resolvedOptions(): Intl.ResolvedNumberFormatOptions {\n let options = this.numberFormatter.resolvedOptions();\n if (!supportsSignDisplay && this.options.signDisplay != null) {\n options = {...options, signDisplay: this.options.signDisplay};\n }\n\n if (!supportsUnit && this.options.style === 'unit') {\n options = {...options, style: 'unit', unit: this.options.unit, unitDisplay: this.options.unitDisplay};\n }\n\n return options;\n }\n}\n\nfunction getCachedNumberFormatter(locale: string, options: NumberFormatOptions = {}): Intl.NumberFormat {\n let {numberingSystem} = options;\n if (numberingSystem && locale.includes('-nu-')) {\n if (!locale.includes('-u-')) {\n locale += '-u-';\n }\n locale += `-nu-${numberingSystem}`;\n }\n\n if (options.style === 'unit' && !supportsUnit) {\n let {unit, unitDisplay = 'short'} = options;\n if (!unit) {\n throw new Error('unit option must be provided with style: \"unit\"');\n }\n if (!UNITS[unit]?.[unitDisplay]) {\n throw new Error(`Unsupported unit ${unit} with unitDisplay = ${unitDisplay}`);\n }\n options = {...options, style: 'decimal'};\n }\n\n let cacheKey = locale + (options ? Object.entries(options).sort((a, b) => a[0] < b[0] ? -1 : 1).join() : '');\n if (formatterCache.has(cacheKey)) {\n return formatterCache.get(cacheKey)!;\n }\n\n let numberFormatter = new Intl.NumberFormat(locale, options);\n formatterCache.set(cacheKey, numberFormatter);\n return numberFormatter;\n}\n\n/** @private - exported for tests */\nexport function numberFormatSignDisplayPolyfill(numberFormat: Intl.NumberFormat, signDisplay: string, num: number): string {\n if (signDisplay === 'auto') {\n return numberFormat.format(num);\n } else if (signDisplay === 'never') {\n return numberFormat.format(Math.abs(num));\n } else {\n let needsPositiveSign = false;\n if (signDisplay === 'always') {\n needsPositiveSign = num > 0 || Object.is(num, 0);\n } else if (signDisplay === 'exceptZero') {\n if (Object.is(num, -0) || Object.is(num, 0)) {\n num = Math.abs(num);\n } else {\n needsPositiveSign = num > 0;\n }\n }\n\n if (needsPositiveSign) {\n let negative = numberFormat.format(-num);\n let noSign = numberFormat.format(num);\n // ignore RTL/LTR marker character\n let minus = negative.replace(noSign, '').replace(/\\u200e|\\u061C/, '');\n if ([...minus].length !== 1) {\n console.warn('@react-aria/i18n polyfill for NumberFormat signDisplay: Unsupported case');\n }\n let positive = negative.replace(noSign, '!!!').replace(minus, '+').replace('!!!', noSign);\n return positive;\n } else {\n return numberFormat.format(num);\n }\n }\n}\n"],"names":[],"version":3,"file":"NumberFormatter.cjs.map"}
1
+ {"mappings":";;;;;;AAAA;;;;;;;;;;CAUC,GAED,IAAI,uCAAiB,IAAI;AAEzB,IAAI,4CAAsB;AAC1B,IAAI;IACF,4CACE,IAAI,KAAK,YAAY,CAAC,SAAS;QAAC,aAAa;IAAY,GAAG,eAAe,GAAG,WAAW,KACzF;AACF,oCAAoC;AACtC,EAAE,OAAM,CAAC;AAET,IAAI,qCAAe;AACnB,IAAI;IACF,qCACE,IAAI,KAAK,YAAY,CAAC,SAAS;QAAC,OAAO;QAAQ,MAAM;IAAQ,GAAG,eAAe,GAAG,KAAK,KACvF;AACF,oCAAoC;AACtC,EAAE,OAAM,CAAC;AAET,gHAAgH;AAChH,wGAAwG;AACxG,yEAAyE;AACzE,MAAM,8BAAQ;IACZ,QAAQ;QACN,QAAQ;YACN,SAAS;YACT,SAAS;YACT,SAAS;YACT,SAAS;QAGX;IACF;AACF;AAeO,MAAM;IAIX,YAAY,MAAc,EAAE,UAA+B,CAAC,CAAC,CAAE;QAC7D,IAAI,CAAC,eAAe,GAAG,+CAAyB,QAAQ;QACxD,IAAI,CAAC,OAAO,GAAG;IACjB;IAEA;;;GAGC,GACD,OAAO,KAAa,EAAU;QAC5B,IAAI,MAAM;QACV,IAAI,CAAC,6CAAuB,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,MACtD,MAAM,0CAAgC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE;aAEtF,MAAM,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC;QAGpC,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,UAAU,CAAC,oCAAc;YAClD,IAAI,QAAC,IAAI,eAAE,cAAc,iBAAS,MAAM,EAAC,GAAG,IAAI,CAAC,eAAe;YAChE,IAAI,CAAC,MACH,OAAO;YAET,IAAI,SAAS,2BAAK,CAAC,KAAK,EAAE,CAAC,YAAY;YACvC,OAAO,MAAM,CAAC,OAAO,IAAI,OAAO,OAAO;QACzC;QAEA,OAAO;IACT;IAEA,6FAA6F,GAC7F,cAAc,KAAa,EAA2B;QACpD,gDAAgD;QAChD,OAAO,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC;IAC5C;IAEA,wCAAwC,GACxC,YAAY,KAAa,EAAE,GAAW,EAAU;QAC9C,IAAI,OAAO,IAAI,CAAC,eAAe,CAAC,WAAW,KAAK,YAC9C,OAAO,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC,OAAO;QAGjD,IAAI,MAAM,OACR,MAAM,IAAI,WAAW;QAGvB,wCAAwC;QACxC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,UAAG,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;IACtD;IAEA,iDAAiD,GACjD,mBAAmB,KAAa,EAAE,GAAW,EAA2B;QACtE,IAAI,OAAO,IAAI,CAAC,eAAe,CAAC,kBAAkB,KAAK,YACrD,OAAO,IAAI,CAAC,eAAe,CAAC,kBAAkB,CAAC,OAAO;QAGxD,IAAI,MAAM,OACR,MAAM,IAAI,WAAW;QAGvB,IAAI,aAAa,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC;QACpD,IAAI,WAAW,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC;QAClD,OAAO;eACF,WAAW,GAAG,CAAC,CAAA,IAAM,CAAA;oBAAC,GAAG,CAAC;oBAAE,QAAQ;gBAAY,CAAA;YACnD;gBAAC,MAAM;gBAAW,OAAO;gBAAO,QAAQ;YAAQ;eAC7C,SAAS,GAAG,CAAC,CAAA,IAAM,CAAA;oBAAC,GAAG,CAAC;oBAAE,QAAQ;gBAAU,CAAA;SAChD;IACH;IAEA,2FAA2F,GAC3F,kBAAoD;QAClD,IAAI,UAAU,IAAI,CAAC,eAAe,CAAC,eAAe;QAClD,IAAI,CAAC,6CAAuB,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,MACtD,UAAU;YAAC,GAAG,OAAO;YAAE,aAAa,IAAI,CAAC,OAAO,CAAC,WAAW;QAAA;QAG9D,IAAI,CAAC,sCAAgB,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,QAC1C,UAAU;YACR,GAAG,OAAO;YACV,OAAO;YACP,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI;YACvB,aAAa,IAAI,CAAC,OAAO,CAAC,WAAW;QACvC;QAGF,OAAO;IACT;AACF;AAEA,SAAS,+CACP,MAAc,EACd,UAA+B,CAAC,CAAC;IAEjC,IAAI,mBAAC,eAAe,EAAC,GAAG;IACxB,IAAI,mBAAmB,OAAO,QAAQ,CAAC,SAAS;QAC9C,IAAI,CAAC,OAAO,QAAQ,CAAC,QACnB,UAAU;QAEZ,UAAU,CAAC,IAAI,EAAE,iBAAiB;IACpC;IAEA,IAAI,QAAQ,KAAK,KAAK,UAAU,CAAC,oCAAc;QAC7C,IAAI,QAAC,IAAI,eAAE,cAAc,SAAQ,GAAG;QACpC,IAAI,CAAC,MACH,MAAM,IAAI,MAAM;QAElB,IAAI,CAAC,2BAAK,CAAC,KAAK,EAAE,CAAC,YAAY,EAC7B,MAAM,IAAI,MAAM,CAAC,iBAAiB,EAAE,KAAK,oBAAoB,EAAE,aAAa;QAE9E,UAAU;YAAC,GAAG,OAAO;YAAE,OAAO;QAAS;IACzC;IAEA,IAAI,WACF,SACC,CAAA,UACG,OAAO,OAAO,CAAC,SACZ,IAAI,CAAC,CAAC,GAAG,IAAO,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,KAAK,GACnC,IAAI,KACP,EAAC;IACP,IAAI,qCAAe,GAAG,CAAC,WACrB,OAAO,qCAAe,GAAG,CAAC;IAG5B,IAAI,kBAAkB,IAAI,KAAK,YAAY,CAAC,QAAQ;IACpD,qCAAe,GAAG,CAAC,UAAU;IAC7B,OAAO;AACT;AAGO,SAAS,0CACd,YAA+B,EAC/B,WAAmB,EACnB,GAAW;IAEX,IAAI,gBAAgB,QAClB,OAAO,aAAa,MAAM,CAAC;SACtB,IAAI,gBAAgB,SACzB,OAAO,aAAa,MAAM,CAAC,KAAK,GAAG,CAAC;SAC/B;QACL,IAAI,oBAAoB;QACxB,IAAI,gBAAgB,UAClB,oBAAoB,MAAM,KAAK,OAAO,EAAE,CAAC,KAAK;aACzC,IAAI,gBAAgB;YACzB,IAAI,OAAO,EAAE,CAAC,KAAK,OAAO,OAAO,EAAE,CAAC,KAAK,IACvC,MAAM,KAAK,GAAG,CAAC;iBAEf,oBAAoB,MAAM;;QAI9B,IAAI,mBAAmB;YACrB,IAAI,WAAW,aAAa,MAAM,CAAC,CAAC;YACpC,IAAI,SAAS,aAAa,MAAM,CAAC;YACjC,kCAAkC;YAClC,IAAI,QAAQ,SAAS,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,iBAAiB;YAClE,IAAI;mBAAI;aAAM,CAAC,MAAM,KAAK,GACxB,QAAQ,IAAI,CAAC;YAEf,IAAI,WAAW,SAAS,OAAO,CAAC,QAAQ,OAAO,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO;YAClF,OAAO;QACT,OACE,OAAO,aAAa,MAAM,CAAC;IAE/B;AACF","sources":["packages/@internationalized/number/src/NumberFormatter.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nlet formatterCache = new Map<string, Intl.NumberFormat>();\n\nlet supportsSignDisplay = false;\ntry {\n supportsSignDisplay =\n new Intl.NumberFormat('de-DE', {signDisplay: 'exceptZero'}).resolvedOptions().signDisplay ===\n 'exceptZero';\n // eslint-disable-next-line no-empty\n} catch {}\n\nlet supportsUnit = false;\ntry {\n supportsUnit =\n new Intl.NumberFormat('de-DE', {style: 'unit', unit: 'degree'}).resolvedOptions().style ===\n 'unit';\n // eslint-disable-next-line no-empty\n} catch {}\n\n// Polyfill for units since Safari doesn't support them yet. See https://bugs.webkit.org/show_bug.cgi?id=215438.\n// Currently only polyfilling the unit degree in narrow format for ColorSlider in our supported locales.\n// Values were determined by switching to each locale manually in Chrome.\nconst UNITS = {\n degree: {\n narrow: {\n default: '°',\n 'ja-JP': ' 度',\n 'zh-TW': '度',\n 'sl-SI': ' °'\n // Arabic?? But Safari already doesn't use Arabic digits so might be ok...\n // https://bugs.webkit.org/show_bug.cgi?id=218139\n }\n }\n};\n\nexport interface NumberFormatOptions extends Intl.NumberFormatOptions {\n /** Overrides default numbering system for the current locale. */\n numberingSystem?: string;\n}\n\ninterface NumberRangeFormatPart extends Intl.NumberFormatPart {\n source: 'startRange' | 'endRange' | 'shared';\n}\n\n/**\n * A wrapper around Intl.NumberFormat providing additional options, polyfills, and caching for\n * performance.\n */\nexport class NumberFormatter implements Intl.NumberFormat {\n private numberFormatter: Intl.NumberFormat;\n private options: NumberFormatOptions;\n\n constructor(locale: string, options: NumberFormatOptions = {}) {\n this.numberFormatter = getCachedNumberFormatter(locale, options);\n this.options = options;\n }\n\n /**\n * Formats a number value as a string, according to the locale and options provided to the\n * constructor.\n */\n format(value: number): string {\n let res = '';\n if (!supportsSignDisplay && this.options.signDisplay != null) {\n res = numberFormatSignDisplayPolyfill(this.numberFormatter, this.options.signDisplay, value);\n } else {\n res = this.numberFormatter.format(value);\n }\n\n if (this.options.style === 'unit' && !supportsUnit) {\n let {unit, unitDisplay = 'short', locale} = this.resolvedOptions();\n if (!unit) {\n return res;\n }\n let values = UNITS[unit]?.[unitDisplay];\n res += values[locale] || values.default;\n }\n\n return res;\n }\n\n /** Formats a number to an array of parts such as separators, digits, punctuation, and more. */\n formatToParts(value: number): Intl.NumberFormatPart[] {\n // TODO: implement signDisplay for formatToParts\n return this.numberFormatter.formatToParts(value);\n }\n\n /** Formats a number range as a string. */\n formatRange(start: number, end: number): string {\n if (typeof this.numberFormatter.formatRange === 'function') {\n return this.numberFormatter.formatRange(start, end);\n }\n\n if (end < start) {\n throw new RangeError('End date must be >= start date');\n }\n\n // Very basic fallback for old browsers.\n return `${this.format(start)} – ${this.format(end)}`;\n }\n\n /** Formats a number range as an array of parts. */\n formatRangeToParts(start: number, end: number): NumberRangeFormatPart[] {\n if (typeof this.numberFormatter.formatRangeToParts === 'function') {\n return this.numberFormatter.formatRangeToParts(start, end);\n }\n\n if (end < start) {\n throw new RangeError('End date must be >= start date');\n }\n\n let startParts = this.numberFormatter.formatToParts(start);\n let endParts = this.numberFormatter.formatToParts(end);\n return [\n ...startParts.map(p => ({...p, source: 'startRange'}) as NumberRangeFormatPart),\n {type: 'literal', value: ' – ', source: 'shared'},\n ...endParts.map(p => ({...p, source: 'endRange'}) as NumberRangeFormatPart)\n ];\n }\n\n /** Returns the resolved formatting options based on the values passed to the constructor. */\n resolvedOptions(): Intl.ResolvedNumberFormatOptions {\n let options = this.numberFormatter.resolvedOptions();\n if (!supportsSignDisplay && this.options.signDisplay != null) {\n options = {...options, signDisplay: this.options.signDisplay};\n }\n\n if (!supportsUnit && this.options.style === 'unit') {\n options = {\n ...options,\n style: 'unit',\n unit: this.options.unit,\n unitDisplay: this.options.unitDisplay\n };\n }\n\n return options;\n }\n}\n\nfunction getCachedNumberFormatter(\n locale: string,\n options: NumberFormatOptions = {}\n): Intl.NumberFormat {\n let {numberingSystem} = options;\n if (numberingSystem && locale.includes('-nu-')) {\n if (!locale.includes('-u-')) {\n locale += '-u-';\n }\n locale += `-nu-${numberingSystem}`;\n }\n\n if (options.style === 'unit' && !supportsUnit) {\n let {unit, unitDisplay = 'short'} = options;\n if (!unit) {\n throw new Error('unit option must be provided with style: \"unit\"');\n }\n if (!UNITS[unit]?.[unitDisplay]) {\n throw new Error(`Unsupported unit ${unit} with unitDisplay = ${unitDisplay}`);\n }\n options = {...options, style: 'decimal'};\n }\n\n let cacheKey =\n locale +\n (options\n ? Object.entries(options)\n .sort((a, b) => (a[0] < b[0] ? -1 : 1))\n .join()\n : '');\n if (formatterCache.has(cacheKey)) {\n return formatterCache.get(cacheKey)!;\n }\n\n let numberFormatter = new Intl.NumberFormat(locale, options);\n formatterCache.set(cacheKey, numberFormatter);\n return numberFormatter;\n}\n\n/** @private - Exported for tests */\nexport function numberFormatSignDisplayPolyfill(\n numberFormat: Intl.NumberFormat,\n signDisplay: string,\n num: number\n): string {\n if (signDisplay === 'auto') {\n return numberFormat.format(num);\n } else if (signDisplay === 'never') {\n return numberFormat.format(Math.abs(num));\n } else {\n let needsPositiveSign = false;\n if (signDisplay === 'always') {\n needsPositiveSign = num > 0 || Object.is(num, 0);\n } else if (signDisplay === 'exceptZero') {\n if (Object.is(num, -0) || Object.is(num, 0)) {\n num = Math.abs(num);\n } else {\n needsPositiveSign = num > 0;\n }\n }\n\n if (needsPositiveSign) {\n let negative = numberFormat.format(-num);\n let noSign = numberFormat.format(num);\n // ignore RTL/LTR marker character\n let minus = negative.replace(noSign, '').replace(/\\u200e|\\u061C/, '');\n if ([...minus].length !== 1) {\n console.warn('@react-aria/i18n polyfill for NumberFormat signDisplay: Unsupported case');\n }\n let positive = negative.replace(noSign, '!!!').replace(minus, '+').replace('!!!', noSign);\n return positive;\n } else {\n return numberFormat.format(num);\n }\n }\n}\n"],"names":[],"version":3,"file":"NumberFormatter.cjs.map"}
@@ -38,7 +38,10 @@ const $6c0bb0183c96ba81$var$UNITS = {
38
38
  }
39
39
  };
40
40
  class $6c0bb0183c96ba81$export$cc77c4ff7e8673c5 {
41
- /** Formats a number value as a string, according to the locale and options provided to the constructor. */ format(value) {
41
+ /**
42
+ * Formats a number value as a string, according to the locale and options provided to the
43
+ * constructor.
44
+ */ format(value) {
42
45
  let res = '';
43
46
  if (!$6c0bb0183c96ba81$var$supportsSignDisplay && this.options.signDisplay != null) res = $6c0bb0183c96ba81$export$711b50b3c525e0f2(this.numberFormatter, this.options.signDisplay, value);
44
47
  else res = this.numberFormatter.format(value);
@@ -1 +1 @@
1
- {"mappings":"AAAA;;;;;;;;;;CAUC,GAED,IAAI,uCAAiB,IAAI;AAEzB,IAAI,4CAAsB;AAC1B,IAAI;IACF,4CAAsB,AAAC,IAAI,KAAK,YAAY,CAAC,SAAS;QAAC,aAAa;IAAY,GAAI,eAAe,GAAG,WAAW,KAAK;AACtH,oCAAoC;AACtC,EAAE,OAAM,CAAC;AAET,IAAI,qCAAe;AACnB,IAAI;IACF,qCAAe,AAAC,IAAI,KAAK,YAAY,CAAC,SAAS;QAAC,OAAO;QAAQ,MAAM;IAAQ,GAAI,eAAe,GAAG,KAAK,KAAK;AAC7G,oCAAoC;AACtC,EAAE,OAAM,CAAC;AAET,gHAAgH;AAChH,wGAAwG;AACxG,yEAAyE;AACzE,MAAM,8BAAQ;IACZ,QAAQ;QACN,QAAQ;YACN,SAAS;YACT,SAAS;YACT,SAAS;YACT,SAAS;QAGX;IACF;AACF;AAcO,MAAM;IASX,yGAAyG,GACzG,OAAO,KAAa,EAAU;QAC5B,IAAI,MAAM;QACV,IAAI,CAAC,6CAAuB,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,MACtD,MAAM,0CAAgC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE;aAEtF,MAAM,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC;QAGpC,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,UAAU,CAAC,oCAAc;gBAKrC;YAJb,IAAI,QAAC,IAAI,eAAE,cAAc,iBAAS,MAAM,EAAC,GAAG,IAAI,CAAC,eAAe;YAChE,IAAI,CAAC,MACH,OAAO;YAET,IAAI,UAAS,cAAA,2BAAK,CAAC,KAAK,cAAX,kCAAA,WAAa,CAAC,YAAY;YACvC,OAAO,MAAM,CAAC,OAAO,IAAI,OAAO,OAAO;QACzC;QAEA,OAAO;IACT;IAEA,6FAA6F,GAC7F,cAAc,KAAa,EAA2B;QACpD,gDAAgD;QAChD,OAAO,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC;IAC5C;IAEA,wCAAwC,GACxC,YAAY,KAAa,EAAE,GAAW,EAAU;QAC9C,IAAI,OAAO,IAAI,CAAC,eAAe,CAAC,WAAW,KAAK,YAC9C,OAAO,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC,OAAO;QAGjD,IAAI,MAAM,OACR,MAAM,IAAI,WAAW;QAGvB,wCAAwC;QACxC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,UAAG,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;IACtD;IAEA,iDAAiD,GACjD,mBAAmB,KAAa,EAAE,GAAW,EAA2B;QACtE,IAAI,OAAO,IAAI,CAAC,eAAe,CAAC,kBAAkB,KAAK,YACrD,OAAO,IAAI,CAAC,eAAe,CAAC,kBAAkB,CAAC,OAAO;QAGxD,IAAI,MAAM,OACR,MAAM,IAAI,WAAW;QAGvB,IAAI,aAAa,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC;QACpD,IAAI,WAAW,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC;QAClD,OAAO;eACF,WAAW,GAAG,CAAC,CAAA,IAAM,CAAA;oBAAC,GAAG,CAAC;oBAAE,QAAQ;gBAAY,CAAA;YACnD;gBAAC,MAAM;gBAAW,OAAO;gBAAO,QAAQ;YAAQ;eAC7C,SAAS,GAAG,CAAC,CAAA,IAAM,CAAA;oBAAC,GAAG,CAAC;oBAAE,QAAQ;gBAAU,CAAA;SAChD;IACH;IAEA,2FAA2F,GAC3F,kBAAoD;QAClD,IAAI,UAAU,IAAI,CAAC,eAAe,CAAC,eAAe;QAClD,IAAI,CAAC,6CAAuB,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,MACtD,UAAU;YAAC,GAAG,OAAO;YAAE,aAAa,IAAI,CAAC,OAAO,CAAC,WAAW;QAAA;QAG9D,IAAI,CAAC,sCAAgB,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,QAC1C,UAAU;YAAC,GAAG,OAAO;YAAE,OAAO;YAAQ,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI;YAAE,aAAa,IAAI,CAAC,OAAO,CAAC,WAAW;QAAA;QAGtG,OAAO;IACT;IA7EA,YAAY,MAAc,EAAE,UAA+B,CAAC,CAAC,CAAE;QAC7D,IAAI,CAAC,eAAe,GAAG,+CAAyB,QAAQ;QACxD,IAAI,CAAC,OAAO,GAAG;IACjB;AA2EF;AAEA,SAAS,+CAAyB,MAAc,EAAE,UAA+B,CAAC,CAAC;IACjF,IAAI,mBAAC,eAAe,EAAC,GAAG;IACxB,IAAI,mBAAmB,OAAO,QAAQ,CAAC,SAAS;QAC9C,IAAI,CAAC,OAAO,QAAQ,CAAC,QACnB,UAAU;QAEZ,UAAU,CAAC,IAAI,EAAE,iBAAiB;IACpC;IAEA,IAAI,QAAQ,KAAK,KAAK,UAAU,CAAC,oCAAc;YAKxC;QAJL,IAAI,QAAC,IAAI,eAAE,cAAc,SAAQ,GAAG;QACpC,IAAI,CAAC,MACH,MAAM,IAAI,MAAM;QAElB,IAAI,GAAC,cAAA,2BAAK,CAAC,KAAK,cAAX,kCAAA,WAAa,CAAC,YAAY,GAC7B,MAAM,IAAI,MAAM,CAAC,iBAAiB,EAAE,KAAK,oBAAoB,EAAE,aAAa;QAE9E,UAAU;YAAC,GAAG,OAAO;YAAE,OAAO;QAAS;IACzC;IAEA,IAAI,WAAW,SAAU,CAAA,UAAU,OAAO,OAAO,CAAC,SAAS,IAAI,CAAC,CAAC,GAAG,IAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,KAAK,GAAG,IAAI,KAAK,EAAC;IAC1G,IAAI,qCAAe,GAAG,CAAC,WACrB,OAAO,qCAAe,GAAG,CAAC;IAG5B,IAAI,kBAAkB,IAAI,KAAK,YAAY,CAAC,QAAQ;IACpD,qCAAe,GAAG,CAAC,UAAU;IAC7B,OAAO;AACT;AAGO,SAAS,0CAAgC,YAA+B,EAAE,WAAmB,EAAE,GAAW;IAC/G,IAAI,gBAAgB,QAClB,OAAO,aAAa,MAAM,CAAC;SACtB,IAAI,gBAAgB,SACzB,OAAO,aAAa,MAAM,CAAC,KAAK,GAAG,CAAC;SAC/B;QACL,IAAI,oBAAoB;QACxB,IAAI,gBAAgB,UAClB,oBAAoB,MAAM,KAAK,OAAO,EAAE,CAAC,KAAK;aACzC,IAAI,gBAAgB;YACzB,IAAI,OAAO,EAAE,CAAC,KAAK,OAAO,OAAO,EAAE,CAAC,KAAK,IACvC,MAAM,KAAK,GAAG,CAAC;iBAEf,oBAAoB,MAAM;;QAI9B,IAAI,mBAAmB;YACrB,IAAI,WAAW,aAAa,MAAM,CAAC,CAAC;YACpC,IAAI,SAAS,aAAa,MAAM,CAAC;YACjC,kCAAkC;YAClC,IAAI,QAAQ,SAAS,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,iBAAiB;YAClE,IAAI;mBAAI;aAAM,CAAC,MAAM,KAAK,GACxB,QAAQ,IAAI,CAAC;YAEf,IAAI,WAAW,SAAS,OAAO,CAAC,QAAQ,OAAO,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO;YAClF,OAAO;QACT,OACE,OAAO,aAAa,MAAM,CAAC;IAE/B;AACF","sources":["packages/@internationalized/number/src/NumberFormatter.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nlet formatterCache = new Map<string, Intl.NumberFormat>();\n\nlet supportsSignDisplay = false;\ntry {\n supportsSignDisplay = (new Intl.NumberFormat('de-DE', {signDisplay: 'exceptZero'})).resolvedOptions().signDisplay === 'exceptZero';\n // eslint-disable-next-line no-empty\n} catch {}\n\nlet supportsUnit = false;\ntry {\n supportsUnit = (new Intl.NumberFormat('de-DE', {style: 'unit', unit: 'degree'})).resolvedOptions().style === 'unit';\n // eslint-disable-next-line no-empty\n} catch {}\n\n// Polyfill for units since Safari doesn't support them yet. See https://bugs.webkit.org/show_bug.cgi?id=215438.\n// Currently only polyfilling the unit degree in narrow format for ColorSlider in our supported locales.\n// Values were determined by switching to each locale manually in Chrome.\nconst UNITS = {\n degree: {\n narrow: {\n default: '°',\n 'ja-JP': ' 度',\n 'zh-TW': '度',\n 'sl-SI': ' °'\n // Arabic?? But Safari already doesn't use Arabic digits so might be ok...\n // https://bugs.webkit.org/show_bug.cgi?id=218139\n }\n }\n};\n\nexport interface NumberFormatOptions extends Intl.NumberFormatOptions {\n /** Overrides default numbering system for the current locale. */\n numberingSystem?: string\n}\n\ninterface NumberRangeFormatPart extends Intl.NumberFormatPart {\n source: 'startRange' | 'endRange' | 'shared'\n}\n\n/**\n * A wrapper around Intl.NumberFormat providing additional options, polyfills, and caching for performance.\n */\nexport class NumberFormatter implements Intl.NumberFormat {\n private numberFormatter: Intl.NumberFormat;\n private options: NumberFormatOptions;\n\n constructor(locale: string, options: NumberFormatOptions = {}) {\n this.numberFormatter = getCachedNumberFormatter(locale, options);\n this.options = options;\n }\n\n /** Formats a number value as a string, according to the locale and options provided to the constructor. */\n format(value: number): string {\n let res = '';\n if (!supportsSignDisplay && this.options.signDisplay != null) {\n res = numberFormatSignDisplayPolyfill(this.numberFormatter, this.options.signDisplay, value);\n } else {\n res = this.numberFormatter.format(value);\n }\n\n if (this.options.style === 'unit' && !supportsUnit) {\n let {unit, unitDisplay = 'short', locale} = this.resolvedOptions();\n if (!unit) {\n return res;\n }\n let values = UNITS[unit]?.[unitDisplay];\n res += values[locale] || values.default;\n }\n\n return res;\n }\n\n /** Formats a number to an array of parts such as separators, digits, punctuation, and more. */\n formatToParts(value: number): Intl.NumberFormatPart[] {\n // TODO: implement signDisplay for formatToParts\n return this.numberFormatter.formatToParts(value);\n }\n\n /** Formats a number range as a string. */\n formatRange(start: number, end: number): string {\n if (typeof this.numberFormatter.formatRange === 'function') {\n return this.numberFormatter.formatRange(start, end);\n }\n\n if (end < start) {\n throw new RangeError('End date must be >= start date');\n }\n\n // Very basic fallback for old browsers.\n return `${this.format(start)} – ${this.format(end)}`;\n }\n\n /** Formats a number range as an array of parts. */\n formatRangeToParts(start: number, end: number): NumberRangeFormatPart[] {\n if (typeof this.numberFormatter.formatRangeToParts === 'function') {\n return this.numberFormatter.formatRangeToParts(start, end);\n }\n\n if (end < start) {\n throw new RangeError('End date must be >= start date');\n }\n\n let startParts = this.numberFormatter.formatToParts(start);\n let endParts = this.numberFormatter.formatToParts(end);\n return [\n ...startParts.map(p => ({...p, source: 'startRange'} as NumberRangeFormatPart)),\n {type: 'literal', value: ' – ', source: 'shared'},\n ...endParts.map(p => ({...p, source: 'endRange'} as NumberRangeFormatPart))\n ];\n }\n\n /** Returns the resolved formatting options based on the values passed to the constructor. */\n resolvedOptions(): Intl.ResolvedNumberFormatOptions {\n let options = this.numberFormatter.resolvedOptions();\n if (!supportsSignDisplay && this.options.signDisplay != null) {\n options = {...options, signDisplay: this.options.signDisplay};\n }\n\n if (!supportsUnit && this.options.style === 'unit') {\n options = {...options, style: 'unit', unit: this.options.unit, unitDisplay: this.options.unitDisplay};\n }\n\n return options;\n }\n}\n\nfunction getCachedNumberFormatter(locale: string, options: NumberFormatOptions = {}): Intl.NumberFormat {\n let {numberingSystem} = options;\n if (numberingSystem && locale.includes('-nu-')) {\n if (!locale.includes('-u-')) {\n locale += '-u-';\n }\n locale += `-nu-${numberingSystem}`;\n }\n\n if (options.style === 'unit' && !supportsUnit) {\n let {unit, unitDisplay = 'short'} = options;\n if (!unit) {\n throw new Error('unit option must be provided with style: \"unit\"');\n }\n if (!UNITS[unit]?.[unitDisplay]) {\n throw new Error(`Unsupported unit ${unit} with unitDisplay = ${unitDisplay}`);\n }\n options = {...options, style: 'decimal'};\n }\n\n let cacheKey = locale + (options ? Object.entries(options).sort((a, b) => a[0] < b[0] ? -1 : 1).join() : '');\n if (formatterCache.has(cacheKey)) {\n return formatterCache.get(cacheKey)!;\n }\n\n let numberFormatter = new Intl.NumberFormat(locale, options);\n formatterCache.set(cacheKey, numberFormatter);\n return numberFormatter;\n}\n\n/** @private - exported for tests */\nexport function numberFormatSignDisplayPolyfill(numberFormat: Intl.NumberFormat, signDisplay: string, num: number): string {\n if (signDisplay === 'auto') {\n return numberFormat.format(num);\n } else if (signDisplay === 'never') {\n return numberFormat.format(Math.abs(num));\n } else {\n let needsPositiveSign = false;\n if (signDisplay === 'always') {\n needsPositiveSign = num > 0 || Object.is(num, 0);\n } else if (signDisplay === 'exceptZero') {\n if (Object.is(num, -0) || Object.is(num, 0)) {\n num = Math.abs(num);\n } else {\n needsPositiveSign = num > 0;\n }\n }\n\n if (needsPositiveSign) {\n let negative = numberFormat.format(-num);\n let noSign = numberFormat.format(num);\n // ignore RTL/LTR marker character\n let minus = negative.replace(noSign, '').replace(/\\u200e|\\u061C/, '');\n if ([...minus].length !== 1) {\n console.warn('@react-aria/i18n polyfill for NumberFormat signDisplay: Unsupported case');\n }\n let positive = negative.replace(noSign, '!!!').replace(minus, '+').replace('!!!', noSign);\n return positive;\n } else {\n return numberFormat.format(num);\n }\n }\n}\n"],"names":[],"version":3,"file":"NumberFormatter.js.map"}
1
+ {"mappings":"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","sources":["packages/@internationalized/number/src/NumberFormatter.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nlet formatterCache = new Map<string, Intl.NumberFormat>();\n\nlet supportsSignDisplay = false;\ntry {\n supportsSignDisplay =\n new Intl.NumberFormat('de-DE', {signDisplay: 'exceptZero'}).resolvedOptions().signDisplay ===\n 'exceptZero';\n // eslint-disable-next-line no-empty\n} catch {}\n\nlet supportsUnit = false;\ntry {\n supportsUnit =\n new Intl.NumberFormat('de-DE', {style: 'unit', unit: 'degree'}).resolvedOptions().style ===\n 'unit';\n // eslint-disable-next-line no-empty\n} catch {}\n\n// Polyfill for units since Safari doesn't support them yet. See https://bugs.webkit.org/show_bug.cgi?id=215438.\n// Currently only polyfilling the unit degree in narrow format for ColorSlider in our supported locales.\n// Values were determined by switching to each locale manually in Chrome.\nconst UNITS = {\n degree: {\n narrow: {\n default: '°',\n 'ja-JP': ' 度',\n 'zh-TW': '度',\n 'sl-SI': ' °'\n // Arabic?? But Safari already doesn't use Arabic digits so might be ok...\n // https://bugs.webkit.org/show_bug.cgi?id=218139\n }\n }\n};\n\nexport interface NumberFormatOptions extends Intl.NumberFormatOptions {\n /** Overrides default numbering system for the current locale. */\n numberingSystem?: string;\n}\n\ninterface NumberRangeFormatPart extends Intl.NumberFormatPart {\n source: 'startRange' | 'endRange' | 'shared';\n}\n\n/**\n * A wrapper around Intl.NumberFormat providing additional options, polyfills, and caching for\n * performance.\n */\nexport class NumberFormatter implements Intl.NumberFormat {\n private numberFormatter: Intl.NumberFormat;\n private options: NumberFormatOptions;\n\n constructor(locale: string, options: NumberFormatOptions = {}) {\n this.numberFormatter = getCachedNumberFormatter(locale, options);\n this.options = options;\n }\n\n /**\n * Formats a number value as a string, according to the locale and options provided to the\n * constructor.\n */\n format(value: number): string {\n let res = '';\n if (!supportsSignDisplay && this.options.signDisplay != null) {\n res = numberFormatSignDisplayPolyfill(this.numberFormatter, this.options.signDisplay, value);\n } else {\n res = this.numberFormatter.format(value);\n }\n\n if (this.options.style === 'unit' && !supportsUnit) {\n let {unit, unitDisplay = 'short', locale} = this.resolvedOptions();\n if (!unit) {\n return res;\n }\n let values = UNITS[unit]?.[unitDisplay];\n res += values[locale] || values.default;\n }\n\n return res;\n }\n\n /** Formats a number to an array of parts such as separators, digits, punctuation, and more. */\n formatToParts(value: number): Intl.NumberFormatPart[] {\n // TODO: implement signDisplay for formatToParts\n return this.numberFormatter.formatToParts(value);\n }\n\n /** Formats a number range as a string. */\n formatRange(start: number, end: number): string {\n if (typeof this.numberFormatter.formatRange === 'function') {\n return this.numberFormatter.formatRange(start, end);\n }\n\n if (end < start) {\n throw new RangeError('End date must be >= start date');\n }\n\n // Very basic fallback for old browsers.\n return `${this.format(start)} – ${this.format(end)}`;\n }\n\n /** Formats a number range as an array of parts. */\n formatRangeToParts(start: number, end: number): NumberRangeFormatPart[] {\n if (typeof this.numberFormatter.formatRangeToParts === 'function') {\n return this.numberFormatter.formatRangeToParts(start, end);\n }\n\n if (end < start) {\n throw new RangeError('End date must be >= start date');\n }\n\n let startParts = this.numberFormatter.formatToParts(start);\n let endParts = this.numberFormatter.formatToParts(end);\n return [\n ...startParts.map(p => ({...p, source: 'startRange'}) as NumberRangeFormatPart),\n {type: 'literal', value: ' – ', source: 'shared'},\n ...endParts.map(p => ({...p, source: 'endRange'}) as NumberRangeFormatPart)\n ];\n }\n\n /** Returns the resolved formatting options based on the values passed to the constructor. */\n resolvedOptions(): Intl.ResolvedNumberFormatOptions {\n let options = this.numberFormatter.resolvedOptions();\n if (!supportsSignDisplay && this.options.signDisplay != null) {\n options = {...options, signDisplay: this.options.signDisplay};\n }\n\n if (!supportsUnit && this.options.style === 'unit') {\n options = {\n ...options,\n style: 'unit',\n unit: this.options.unit,\n unitDisplay: this.options.unitDisplay\n };\n }\n\n return options;\n }\n}\n\nfunction getCachedNumberFormatter(\n locale: string,\n options: NumberFormatOptions = {}\n): Intl.NumberFormat {\n let {numberingSystem} = options;\n if (numberingSystem && locale.includes('-nu-')) {\n if (!locale.includes('-u-')) {\n locale += '-u-';\n }\n locale += `-nu-${numberingSystem}`;\n }\n\n if (options.style === 'unit' && !supportsUnit) {\n let {unit, unitDisplay = 'short'} = options;\n if (!unit) {\n throw new Error('unit option must be provided with style: \"unit\"');\n }\n if (!UNITS[unit]?.[unitDisplay]) {\n throw new Error(`Unsupported unit ${unit} with unitDisplay = ${unitDisplay}`);\n }\n options = {...options, style: 'decimal'};\n }\n\n let cacheKey =\n locale +\n (options\n ? Object.entries(options)\n .sort((a, b) => (a[0] < b[0] ? -1 : 1))\n .join()\n : '');\n if (formatterCache.has(cacheKey)) {\n return formatterCache.get(cacheKey)!;\n }\n\n let numberFormatter = new Intl.NumberFormat(locale, options);\n formatterCache.set(cacheKey, numberFormatter);\n return numberFormatter;\n}\n\n/** @private - Exported for tests */\nexport function numberFormatSignDisplayPolyfill(\n numberFormat: Intl.NumberFormat,\n signDisplay: string,\n num: number\n): string {\n if (signDisplay === 'auto') {\n return numberFormat.format(num);\n } else if (signDisplay === 'never') {\n return numberFormat.format(Math.abs(num));\n } else {\n let needsPositiveSign = false;\n if (signDisplay === 'always') {\n needsPositiveSign = num > 0 || Object.is(num, 0);\n } else if (signDisplay === 'exceptZero') {\n if (Object.is(num, -0) || Object.is(num, 0)) {\n num = Math.abs(num);\n } else {\n needsPositiveSign = num > 0;\n }\n }\n\n if (needsPositiveSign) {\n let negative = numberFormat.format(-num);\n let noSign = numberFormat.format(num);\n // ignore RTL/LTR marker character\n let minus = negative.replace(noSign, '').replace(/\\u200e|\\u061C/, '');\n if ([...minus].length !== 1) {\n console.warn('@react-aria/i18n polyfill for NumberFormat signDisplay: Unsupported case');\n }\n let positive = negative.replace(noSign, '!!!').replace(minus, '+').replace('!!!', noSign);\n return positive;\n } else {\n return numberFormat.format(num);\n }\n }\n}\n"],"names":[],"version":3,"file":"NumberFormatter.js.map"}
@@ -42,7 +42,10 @@ class $1dfb119a85e764e5$export$cc77c4ff7e8673c5 {
42
42
  this.numberFormatter = $1dfb119a85e764e5$var$getCachedNumberFormatter(locale, options);
43
43
  this.options = options;
44
44
  }
45
- /** Formats a number value as a string, according to the locale and options provided to the constructor. */ format(value) {
45
+ /**
46
+ * Formats a number value as a string, according to the locale and options provided to the
47
+ * constructor.
48
+ */ format(value) {
46
49
  let res = '';
47
50
  if (!$1dfb119a85e764e5$var$supportsSignDisplay && this.options.signDisplay != null) res = $1dfb119a85e764e5$export$711b50b3c525e0f2(this.numberFormatter, this.options.signDisplay, value);
48
51
  else res = this.numberFormatter.format(value);
@@ -1 +1 @@
1
- {"mappings":"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","sources":["packages/@internationalized/number/src/NumberFormatter.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nlet formatterCache = new Map<string, Intl.NumberFormat>();\n\nlet supportsSignDisplay = false;\ntry {\n supportsSignDisplay = (new Intl.NumberFormat('de-DE', {signDisplay: 'exceptZero'})).resolvedOptions().signDisplay === 'exceptZero';\n // eslint-disable-next-line no-empty\n} catch {}\n\nlet supportsUnit = false;\ntry {\n supportsUnit = (new Intl.NumberFormat('de-DE', {style: 'unit', unit: 'degree'})).resolvedOptions().style === 'unit';\n // eslint-disable-next-line no-empty\n} catch {}\n\n// Polyfill for units since Safari doesn't support them yet. See https://bugs.webkit.org/show_bug.cgi?id=215438.\n// Currently only polyfilling the unit degree in narrow format for ColorSlider in our supported locales.\n// Values were determined by switching to each locale manually in Chrome.\nconst UNITS = {\n degree: {\n narrow: {\n default: '°',\n 'ja-JP': ' 度',\n 'zh-TW': '度',\n 'sl-SI': ' °'\n // Arabic?? But Safari already doesn't use Arabic digits so might be ok...\n // https://bugs.webkit.org/show_bug.cgi?id=218139\n }\n }\n};\n\nexport interface NumberFormatOptions extends Intl.NumberFormatOptions {\n /** Overrides default numbering system for the current locale. */\n numberingSystem?: string\n}\n\ninterface NumberRangeFormatPart extends Intl.NumberFormatPart {\n source: 'startRange' | 'endRange' | 'shared'\n}\n\n/**\n * A wrapper around Intl.NumberFormat providing additional options, polyfills, and caching for performance.\n */\nexport class NumberFormatter implements Intl.NumberFormat {\n private numberFormatter: Intl.NumberFormat;\n private options: NumberFormatOptions;\n\n constructor(locale: string, options: NumberFormatOptions = {}) {\n this.numberFormatter = getCachedNumberFormatter(locale, options);\n this.options = options;\n }\n\n /** Formats a number value as a string, according to the locale and options provided to the constructor. */\n format(value: number): string {\n let res = '';\n if (!supportsSignDisplay && this.options.signDisplay != null) {\n res = numberFormatSignDisplayPolyfill(this.numberFormatter, this.options.signDisplay, value);\n } else {\n res = this.numberFormatter.format(value);\n }\n\n if (this.options.style === 'unit' && !supportsUnit) {\n let {unit, unitDisplay = 'short', locale} = this.resolvedOptions();\n if (!unit) {\n return res;\n }\n let values = UNITS[unit]?.[unitDisplay];\n res += values[locale] || values.default;\n }\n\n return res;\n }\n\n /** Formats a number to an array of parts such as separators, digits, punctuation, and more. */\n formatToParts(value: number): Intl.NumberFormatPart[] {\n // TODO: implement signDisplay for formatToParts\n return this.numberFormatter.formatToParts(value);\n }\n\n /** Formats a number range as a string. */\n formatRange(start: number, end: number): string {\n if (typeof this.numberFormatter.formatRange === 'function') {\n return this.numberFormatter.formatRange(start, end);\n }\n\n if (end < start) {\n throw new RangeError('End date must be >= start date');\n }\n\n // Very basic fallback for old browsers.\n return `${this.format(start)} – ${this.format(end)}`;\n }\n\n /** Formats a number range as an array of parts. */\n formatRangeToParts(start: number, end: number): NumberRangeFormatPart[] {\n if (typeof this.numberFormatter.formatRangeToParts === 'function') {\n return this.numberFormatter.formatRangeToParts(start, end);\n }\n\n if (end < start) {\n throw new RangeError('End date must be >= start date');\n }\n\n let startParts = this.numberFormatter.formatToParts(start);\n let endParts = this.numberFormatter.formatToParts(end);\n return [\n ...startParts.map(p => ({...p, source: 'startRange'} as NumberRangeFormatPart)),\n {type: 'literal', value: ' – ', source: 'shared'},\n ...endParts.map(p => ({...p, source: 'endRange'} as NumberRangeFormatPart))\n ];\n }\n\n /** Returns the resolved formatting options based on the values passed to the constructor. */\n resolvedOptions(): Intl.ResolvedNumberFormatOptions {\n let options = this.numberFormatter.resolvedOptions();\n if (!supportsSignDisplay && this.options.signDisplay != null) {\n options = {...options, signDisplay: this.options.signDisplay};\n }\n\n if (!supportsUnit && this.options.style === 'unit') {\n options = {...options, style: 'unit', unit: this.options.unit, unitDisplay: this.options.unitDisplay};\n }\n\n return options;\n }\n}\n\nfunction getCachedNumberFormatter(locale: string, options: NumberFormatOptions = {}): Intl.NumberFormat {\n let {numberingSystem} = options;\n if (numberingSystem && locale.includes('-nu-')) {\n if (!locale.includes('-u-')) {\n locale += '-u-';\n }\n locale += `-nu-${numberingSystem}`;\n }\n\n if (options.style === 'unit' && !supportsUnit) {\n let {unit, unitDisplay = 'short'} = options;\n if (!unit) {\n throw new Error('unit option must be provided with style: \"unit\"');\n }\n if (!UNITS[unit]?.[unitDisplay]) {\n throw new Error(`Unsupported unit ${unit} with unitDisplay = ${unitDisplay}`);\n }\n options = {...options, style: 'decimal'};\n }\n\n let cacheKey = locale + (options ? Object.entries(options).sort((a, b) => a[0] < b[0] ? -1 : 1).join() : '');\n if (formatterCache.has(cacheKey)) {\n return formatterCache.get(cacheKey)!;\n }\n\n let numberFormatter = new Intl.NumberFormat(locale, options);\n formatterCache.set(cacheKey, numberFormatter);\n return numberFormatter;\n}\n\n/** @private - exported for tests */\nexport function numberFormatSignDisplayPolyfill(numberFormat: Intl.NumberFormat, signDisplay: string, num: number): string {\n if (signDisplay === 'auto') {\n return numberFormat.format(num);\n } else if (signDisplay === 'never') {\n return numberFormat.format(Math.abs(num));\n } else {\n let needsPositiveSign = false;\n if (signDisplay === 'always') {\n needsPositiveSign = num > 0 || Object.is(num, 0);\n } else if (signDisplay === 'exceptZero') {\n if (Object.is(num, -0) || Object.is(num, 0)) {\n num = Math.abs(num);\n } else {\n needsPositiveSign = num > 0;\n }\n }\n\n if (needsPositiveSign) {\n let negative = numberFormat.format(-num);\n let noSign = numberFormat.format(num);\n // ignore RTL/LTR marker character\n let minus = negative.replace(noSign, '').replace(/\\u200e|\\u061C/, '');\n if ([...minus].length !== 1) {\n console.warn('@react-aria/i18n polyfill for NumberFormat signDisplay: Unsupported case');\n }\n let positive = negative.replace(noSign, '!!!').replace(minus, '+').replace('!!!', noSign);\n return positive;\n } else {\n return numberFormat.format(num);\n }\n }\n}\n"],"names":[],"version":3,"file":"NumberFormatter.mjs.map"}
1
+ {"mappings":"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","sources":["packages/@internationalized/number/src/NumberFormatter.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nlet formatterCache = new Map<string, Intl.NumberFormat>();\n\nlet supportsSignDisplay = false;\ntry {\n supportsSignDisplay =\n new Intl.NumberFormat('de-DE', {signDisplay: 'exceptZero'}).resolvedOptions().signDisplay ===\n 'exceptZero';\n // eslint-disable-next-line no-empty\n} catch {}\n\nlet supportsUnit = false;\ntry {\n supportsUnit =\n new Intl.NumberFormat('de-DE', {style: 'unit', unit: 'degree'}).resolvedOptions().style ===\n 'unit';\n // eslint-disable-next-line no-empty\n} catch {}\n\n// Polyfill for units since Safari doesn't support them yet. See https://bugs.webkit.org/show_bug.cgi?id=215438.\n// Currently only polyfilling the unit degree in narrow format for ColorSlider in our supported locales.\n// Values were determined by switching to each locale manually in Chrome.\nconst UNITS = {\n degree: {\n narrow: {\n default: '°',\n 'ja-JP': ' 度',\n 'zh-TW': '度',\n 'sl-SI': ' °'\n // Arabic?? But Safari already doesn't use Arabic digits so might be ok...\n // https://bugs.webkit.org/show_bug.cgi?id=218139\n }\n }\n};\n\nexport interface NumberFormatOptions extends Intl.NumberFormatOptions {\n /** Overrides default numbering system for the current locale. */\n numberingSystem?: string;\n}\n\ninterface NumberRangeFormatPart extends Intl.NumberFormatPart {\n source: 'startRange' | 'endRange' | 'shared';\n}\n\n/**\n * A wrapper around Intl.NumberFormat providing additional options, polyfills, and caching for\n * performance.\n */\nexport class NumberFormatter implements Intl.NumberFormat {\n private numberFormatter: Intl.NumberFormat;\n private options: NumberFormatOptions;\n\n constructor(locale: string, options: NumberFormatOptions = {}) {\n this.numberFormatter = getCachedNumberFormatter(locale, options);\n this.options = options;\n }\n\n /**\n * Formats a number value as a string, according to the locale and options provided to the\n * constructor.\n */\n format(value: number): string {\n let res = '';\n if (!supportsSignDisplay && this.options.signDisplay != null) {\n res = numberFormatSignDisplayPolyfill(this.numberFormatter, this.options.signDisplay, value);\n } else {\n res = this.numberFormatter.format(value);\n }\n\n if (this.options.style === 'unit' && !supportsUnit) {\n let {unit, unitDisplay = 'short', locale} = this.resolvedOptions();\n if (!unit) {\n return res;\n }\n let values = UNITS[unit]?.[unitDisplay];\n res += values[locale] || values.default;\n }\n\n return res;\n }\n\n /** Formats a number to an array of parts such as separators, digits, punctuation, and more. */\n formatToParts(value: number): Intl.NumberFormatPart[] {\n // TODO: implement signDisplay for formatToParts\n return this.numberFormatter.formatToParts(value);\n }\n\n /** Formats a number range as a string. */\n formatRange(start: number, end: number): string {\n if (typeof this.numberFormatter.formatRange === 'function') {\n return this.numberFormatter.formatRange(start, end);\n }\n\n if (end < start) {\n throw new RangeError('End date must be >= start date');\n }\n\n // Very basic fallback for old browsers.\n return `${this.format(start)} – ${this.format(end)}`;\n }\n\n /** Formats a number range as an array of parts. */\n formatRangeToParts(start: number, end: number): NumberRangeFormatPart[] {\n if (typeof this.numberFormatter.formatRangeToParts === 'function') {\n return this.numberFormatter.formatRangeToParts(start, end);\n }\n\n if (end < start) {\n throw new RangeError('End date must be >= start date');\n }\n\n let startParts = this.numberFormatter.formatToParts(start);\n let endParts = this.numberFormatter.formatToParts(end);\n return [\n ...startParts.map(p => ({...p, source: 'startRange'}) as NumberRangeFormatPart),\n {type: 'literal', value: ' – ', source: 'shared'},\n ...endParts.map(p => ({...p, source: 'endRange'}) as NumberRangeFormatPart)\n ];\n }\n\n /** Returns the resolved formatting options based on the values passed to the constructor. */\n resolvedOptions(): Intl.ResolvedNumberFormatOptions {\n let options = this.numberFormatter.resolvedOptions();\n if (!supportsSignDisplay && this.options.signDisplay != null) {\n options = {...options, signDisplay: this.options.signDisplay};\n }\n\n if (!supportsUnit && this.options.style === 'unit') {\n options = {\n ...options,\n style: 'unit',\n unit: this.options.unit,\n unitDisplay: this.options.unitDisplay\n };\n }\n\n return options;\n }\n}\n\nfunction getCachedNumberFormatter(\n locale: string,\n options: NumberFormatOptions = {}\n): Intl.NumberFormat {\n let {numberingSystem} = options;\n if (numberingSystem && locale.includes('-nu-')) {\n if (!locale.includes('-u-')) {\n locale += '-u-';\n }\n locale += `-nu-${numberingSystem}`;\n }\n\n if (options.style === 'unit' && !supportsUnit) {\n let {unit, unitDisplay = 'short'} = options;\n if (!unit) {\n throw new Error('unit option must be provided with style: \"unit\"');\n }\n if (!UNITS[unit]?.[unitDisplay]) {\n throw new Error(`Unsupported unit ${unit} with unitDisplay = ${unitDisplay}`);\n }\n options = {...options, style: 'decimal'};\n }\n\n let cacheKey =\n locale +\n (options\n ? Object.entries(options)\n .sort((a, b) => (a[0] < b[0] ? -1 : 1))\n .join()\n : '');\n if (formatterCache.has(cacheKey)) {\n return formatterCache.get(cacheKey)!;\n }\n\n let numberFormatter = new Intl.NumberFormat(locale, options);\n formatterCache.set(cacheKey, numberFormatter);\n return numberFormatter;\n}\n\n/** @private - Exported for tests */\nexport function numberFormatSignDisplayPolyfill(\n numberFormat: Intl.NumberFormat,\n signDisplay: string,\n num: number\n): string {\n if (signDisplay === 'auto') {\n return numberFormat.format(num);\n } else if (signDisplay === 'never') {\n return numberFormat.format(Math.abs(num));\n } else {\n let needsPositiveSign = false;\n if (signDisplay === 'always') {\n needsPositiveSign = num > 0 || Object.is(num, 0);\n } else if (signDisplay === 'exceptZero') {\n if (Object.is(num, -0) || Object.is(num, 0)) {\n num = Math.abs(num);\n } else {\n needsPositiveSign = num > 0;\n }\n }\n\n if (needsPositiveSign) {\n let negative = numberFormat.format(-num);\n let noSign = numberFormat.format(num);\n // ignore RTL/LTR marker character\n let minus = negative.replace(noSign, '').replace(/\\u200e|\\u061C/, '');\n if ([...minus].length !== 1) {\n console.warn('@react-aria/i18n polyfill for NumberFormat signDisplay: Unsupported case');\n }\n let positive = negative.replace(noSign, '!!!').replace(minus, '+').replace('!!!', noSign);\n return positive;\n } else {\n return numberFormat.format(num);\n }\n }\n}\n"],"names":[],"version":3,"file":"NumberFormatter.mjs.map"}
@@ -155,6 +155,8 @@ class $52ebab2a875d5a2c$var$NumberParserImpl {
155
155
  // In some locale styles, such as swiss currency, the group character can be a special single quote
156
156
  // that keyboards don't typically have. This expands the character to include the easier to type single quote.
157
157
  if (this.symbols.group === "\u2019" && value.includes("'") && isGroupSymbolAllowed) value = $52ebab2a875d5a2c$var$replaceAll(value, "'", this.symbols.group);
158
+ // On newer ICU versions, the special single quote has been normalized, so we need to backport.
159
+ if (this.symbols.group === "'" && value.includes("\u2019") && isGroupSymbolAllowed) value = $52ebab2a875d5a2c$var$replaceAll(value, "\u2019", this.symbols.group);
158
160
  // fr-FR group character is narrow non-breaking space, char code 8239 (U+202F), but that's not a key on the french keyboard,
159
161
  // so allow space and non-breaking space as a group char as well
160
162
  if (this.options.locale === 'fr-FR' && this.symbols.group && isGroupSymbolAllowed) {
@@ -187,9 +189,9 @@ const $52ebab2a875d5a2c$var$nonLiteralParts = new Set([
187
189
  'plusSign',
188
190
  'group'
189
191
  ]);
190
- // This list is derived from https://www.unicode.org/cldr/charts/43/supplemental/language_plural_rules.html#comparison and includes
192
+ // This list is derived from https://www.unicode.org/cldr/charts/49/supplemental/language_plural_rules.html#comparison and includes
191
193
  // all unique numbers which we need to check in order to determine all the plural forms for a given locale.
192
- // See: https://github.com/adobe/react-spectrum/pull/5134/files#r1337037855 for used script
194
+ // Run scripts/generateAllPlurals.mjs to generate this list.
193
195
  const $52ebab2a875d5a2c$var$pluralNumbers = [
194
196
  0,
195
197
  4,
@@ -1 +1 @@
1
- {"mappings":"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","sources":["packages/@internationalized/number/src/NumberParser.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {NumberFormatter} from './NumberFormatter';\n\ninterface Symbols {\n minusSign?: string,\n plusSign?: string,\n decimal?: string,\n group?: string,\n literals: RegExp,\n numeral: RegExp,\n numerals: string[],\n index: (v: string) => string,\n noNumeralUnits: Array<{unit: string, value: number}>\n}\n\nconst CURRENCY_SIGN_REGEX = new RegExp('^.*\\\\(.*\\\\).*$');\nconst NUMBERING_SYSTEMS = ['latn', 'arab', 'hanidec', 'deva', 'beng', 'fullwide'];\n\n/**\n * A NumberParser can be used to perform locale-aware parsing of numbers from Unicode strings,\n * as well as validation of partial user input. It automatically detects the numbering system\n * used in the input, and supports parsing decimals, percentages, currency values, and units\n * according to the locale.\n */\nexport class NumberParser {\n private locale: string;\n private options: Intl.NumberFormatOptions;\n\n constructor(locale: string, options: Intl.NumberFormatOptions = {}) {\n this.locale = locale;\n this.options = options;\n }\n\n /**\n * Parses the given string to a number. Returns NaN if a valid number could not be parsed.\n */\n parse(value: string): number {\n return getNumberParserImpl(this.locale, this.options, value).parse(value);\n }\n\n /**\n * Returns whether the given string could potentially be a valid number. This should be used to\n * validate user input as the user types. If a `minValue` or `maxValue` is provided, the validity\n * of the minus/plus sign characters can be checked.\n */\n isValidPartialNumber(value: string, minValue?: number, maxValue?: number): boolean {\n return getNumberParserImpl(this.locale, this.options, value).isValidPartialNumber(value, minValue, maxValue);\n }\n\n /**\n * Returns a numbering system for which the given string is valid in the current locale.\n * If no numbering system could be detected, the default numbering system for the current\n * locale is returned.\n */\n getNumberingSystem(value: string): string {\n return getNumberParserImpl(this.locale, this.options, value).options.numberingSystem;\n }\n}\n\nconst numberParserCache = new Map<string, NumberParserImpl>();\nfunction getNumberParserImpl(locale: string, options: Intl.NumberFormatOptions, value: string) {\n // First try the default numbering system for the provided locale\n let defaultParser = getCachedNumberParser(locale, options);\n\n // If that doesn't match, and the locale doesn't include a hard coded numbering system,\n // try each of the other supported numbering systems until we find one that matches.\n if (!locale.includes('-nu-') && !defaultParser.isValidPartialNumber(value)) {\n for (let numberingSystem of NUMBERING_SYSTEMS) {\n if (numberingSystem !== defaultParser.options.numberingSystem) {\n let parser = getCachedNumberParser(locale + (locale.includes('-u-') ? '-nu-' : '-u-nu-') + numberingSystem, options);\n if (parser.isValidPartialNumber(value)) {\n return parser;\n }\n }\n }\n }\n\n return defaultParser;\n}\n\nfunction getCachedNumberParser(locale: string, options: Intl.NumberFormatOptions) {\n let cacheKey = locale + (options ? Object.entries(options).sort((a, b) => a[0] < b[0] ? -1 : 1).join() : '');\n let parser = numberParserCache.get(cacheKey);\n if (!parser) {\n parser = new NumberParserImpl(locale, options);\n numberParserCache.set(cacheKey, parser);\n }\n\n return parser;\n}\n\n// The actual number parser implementation. Instances of this class are cached\n// based on the locale, options, and detected numbering system.\nclass NumberParserImpl {\n formatter: Intl.NumberFormat;\n options: Intl.ResolvedNumberFormatOptions;\n symbols: Symbols;\n locale: string;\n\n constructor(locale: string, options: Intl.NumberFormatOptions = {}) {\n this.locale = locale;\n // see https://tc39.es/ecma402/#sec-setnfdigitoptions, when using roundingIncrement, the maximumFractionDigits and minimumFractionDigits must be equal\n // by default, they are 0 and 3 respectively, so we set them to 0 if neither are set\n if (options.roundingIncrement !== 1 && options.roundingIncrement != null) {\n if (options.maximumFractionDigits == null && options.minimumFractionDigits == null) {\n options.maximumFractionDigits = 0;\n options.minimumFractionDigits = 0;\n } else if (options.maximumFractionDigits == null) {\n options.maximumFractionDigits = options.minimumFractionDigits;\n } else if (options.minimumFractionDigits == null) {\n options.minimumFractionDigits = options.maximumFractionDigits;\n }\n // if both are specified, let the normal Range Error be thrown\n }\n this.formatter = new Intl.NumberFormat(locale, options);\n this.options = this.formatter.resolvedOptions();\n this.symbols = getSymbols(locale, this.formatter, this.options, options);\n if (this.options.style === 'percent' && ((this.options.minimumFractionDigits ?? 0) > 18 || (this.options.maximumFractionDigits ?? 0) > 18)) {\n console.warn('NumberParser cannot handle percentages with greater than 18 decimal places, please reduce the number in your options.');\n }\n }\n\n parse(value: string) {\n let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;\n // to parse the number, we need to remove anything that isn't actually part of the number, for example we want '-10.40' not '-10.40 USD'\n let fullySanitizedValue = this.sanitize(value);\n\n // Return NaN if there is a group symbol but useGrouping is false\n if (!isGroupSymbolAllowed && this.symbols.group && fullySanitizedValue.includes(this.symbols.group)) {\n return NaN;\n } else if (this.symbols.group) {\n fullySanitizedValue = fullySanitizedValue.replaceAll(this.symbols.group!, '');\n }\n\n if (this.symbols.decimal) {\n fullySanitizedValue = fullySanitizedValue.replace(this.symbols.decimal!, '.');\n }\n if (this.symbols.minusSign) {\n fullySanitizedValue = fullySanitizedValue.replace(this.symbols.minusSign!, '-');\n }\n fullySanitizedValue = fullySanitizedValue.replace(this.symbols.numeral, this.symbols.index);\n\n if (this.options.style === 'percent') {\n // javascript is bad at dividing by 100 and maintaining the same significant figures, so perform it on the string before parsing\n let isNegative = fullySanitizedValue.indexOf('-');\n fullySanitizedValue = fullySanitizedValue.replace('-', '');\n fullySanitizedValue = fullySanitizedValue.replace('+', '');\n let index = fullySanitizedValue.indexOf('.');\n if (index === -1) {\n index = fullySanitizedValue.length;\n }\n fullySanitizedValue = fullySanitizedValue.replace('.', '');\n if (index - 2 === 0) {\n fullySanitizedValue = `0.${fullySanitizedValue}`;\n } else if (index - 2 === -1) {\n fullySanitizedValue = `0.0${fullySanitizedValue}`;\n } else if (index - 2 === -2) {\n fullySanitizedValue = '0.00';\n } else {\n fullySanitizedValue = `${fullySanitizedValue.slice(0, index - 2)}.${fullySanitizedValue.slice(index - 2)}`;\n }\n if (isNegative > -1) {\n fullySanitizedValue = `-${fullySanitizedValue}`;\n }\n }\n\n let newValue = fullySanitizedValue ? +fullySanitizedValue : NaN;\n if (isNaN(newValue)) {\n return NaN;\n }\n\n if (this.options.style === 'percent') {\n // extra step for rounding percents to what our formatter would output\n let options = {\n ...this.options,\n style: 'decimal' as const,\n minimumFractionDigits: Math.min((this.options.minimumFractionDigits ?? 0) + 2, 20),\n maximumFractionDigits: Math.min((this.options.maximumFractionDigits ?? 0) + 2, 20)\n };\n return (new NumberParser(this.locale, options)).parse(new NumberFormatter(this.locale, options).format(newValue));\n }\n\n // accounting will always be stripped to a positive number, so if it's accounting and has a () around everything, then we need to make it negative again\n if (this.options.currencySign === 'accounting' && CURRENCY_SIGN_REGEX.test(value)) {\n newValue = -1 * newValue;\n }\n return newValue;\n }\n\n sanitize(value: string) {\n let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;\n // If the value is only a unit and it matches one of the formatted numbers where the value is part of the unit and doesn't have any numerals, then\n // return the known value for that case.\n if (this.symbols.noNumeralUnits.length > 0 && this.symbols.noNumeralUnits.find(obj => obj.unit === value)) {\n return this.symbols.noNumeralUnits.find(obj => obj.unit === value)!.value.toString();\n }\n\n value = value.replace(this.symbols.literals, '');\n\n // Replace the ASCII minus sign with the minus sign used in the current locale\n // so that both are allowed in case the user's keyboard doesn't have the locale's minus sign.\n if (this.symbols.minusSign) {\n value = value.replace('-', this.symbols.minusSign);\n }\n\n // In arab numeral system, their decimal character is 1643, but most keyboards don't type that\n // instead they use the , (44) character or apparently the (1548) character.\n if (this.options.numberingSystem === 'arab') {\n if (this.symbols.decimal) {\n value = replaceAll(value, ',', this.symbols.decimal);\n value = replaceAll(value, String.fromCharCode(1548), this.symbols.decimal);\n }\n if (this.symbols.group && isGroupSymbolAllowed) {\n value = replaceAll(value, '.', this.symbols.group);\n }\n }\n\n // In some locale styles, such as swiss currency, the group character can be a special single quote\n // that keyboards don't typically have. This expands the character to include the easier to type single quote.\n if (this.symbols.group === '’' && value.includes(\"'\") && isGroupSymbolAllowed) {\n value = replaceAll(value, \"'\", this.symbols.group);\n }\n\n // fr-FR group character is narrow non-breaking space, char code 8239 (U+202F), but that's not a key on the french keyboard,\n // so allow space and non-breaking space as a group char as well\n if (this.options.locale === 'fr-FR' && this.symbols.group && isGroupSymbolAllowed) {\n value = replaceAll(value, ' ', this.symbols.group);\n value = replaceAll(value, /\\u00A0/g, this.symbols.group);\n }\n\n return value;\n }\n\n isValidPartialNumber(value: string, minValue: number = -Infinity, maxValue: number = Infinity): boolean {\n let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;\n value = this.sanitize(value);\n\n // Remove minus or plus sign, which must be at the start of the string.\n if (this.symbols.minusSign && value.startsWith(this.symbols.minusSign) && minValue < 0) {\n value = value.slice(this.symbols.minusSign.length);\n } else if (this.symbols.plusSign && value.startsWith(this.symbols.plusSign) && maxValue > 0) {\n value = value.slice(this.symbols.plusSign.length);\n }\n\n // Numbers that can't have any decimal values fail if a decimal character is typed\n if (this.symbols.decimal && value.indexOf(this.symbols.decimal) > -1 && this.options.maximumFractionDigits === 0) {\n return false;\n }\n\n // Remove numerals, groups, and decimals\n if (this.symbols.group && isGroupSymbolAllowed) {\n value = replaceAll(value, this.symbols.group, '');\n }\n value = value.replace(this.symbols.numeral, '');\n if (this.symbols.decimal) {\n value = value.replace(this.symbols.decimal, '');\n }\n\n // The number is valid if there are no remaining characters\n return value.length === 0;\n }\n}\n\nconst nonLiteralParts = new Set(['decimal', 'fraction', 'integer', 'minusSign', 'plusSign', 'group']);\n\n// This list is derived from https://www.unicode.org/cldr/charts/43/supplemental/language_plural_rules.html#comparison and includes\n// all unique numbers which we need to check in order to determine all the plural forms for a given locale.\n// See: https://github.com/adobe/react-spectrum/pull/5134/files#r1337037855 for used script\nconst pluralNumbers = [\n 0, 4, 2, 1, 11, 20, 3, 7, 100, 21, 0.1, 1.1\n];\n\nfunction getSymbols(locale: string, formatter: Intl.NumberFormat, intlOptions: Intl.ResolvedNumberFormatOptions, originalOptions: Intl.NumberFormatOptions): Symbols {\n // formatter needs access to all decimal places in order to generate the correct literal strings for the plural set\n let symbolFormatter = new Intl.NumberFormat(locale, {...intlOptions,\n // Resets so we get the full range of symbols\n minimumSignificantDigits: 1,\n maximumSignificantDigits: 21,\n roundingIncrement: 1,\n roundingPriority: 'auto',\n roundingMode: 'halfExpand',\n useGrouping: true\n });\n // Note: some locale's don't add a group symbol until there is a ten thousands place\n let allParts = symbolFormatter.formatToParts(-10000.111);\n let posAllParts = symbolFormatter.formatToParts(10000.111);\n let pluralParts = pluralNumbers.map(n => symbolFormatter.formatToParts(n));\n // if the plural parts include a unit but no integer or fraction, then we need to add the unit to the special set\n let noNumeralUnits = pluralParts.map((p, i) => {\n let unit = p.find(p => p.type === 'unit');\n if (unit && !p.some(p => p.type === 'integer' || p.type === 'fraction')) {\n return {unit: unit.value, value: pluralNumbers[i]};\n }\n return null;\n }).filter(p => !!p);\n\n let minusSign = allParts.find(p => p.type === 'minusSign')?.value ?? '-';\n let plusSign = posAllParts.find(p => p.type === 'plusSign')?.value;\n\n // Safari does not support the signDisplay option, but our number parser polyfills it.\n // If no plus sign was returned, but the original options contained signDisplay, default to the '+' character.\n if (!plusSign && (originalOptions?.signDisplay === 'exceptZero' || originalOptions?.signDisplay === 'always')) {\n plusSign = '+';\n }\n\n // If maximumSignificantDigits is 1 (the minimum) then we won't get decimal characters out of the above formatters\n // Percent also defaults to 0 fractionDigits, so we need to make a new one that isn't percent to get an accurate decimal\n let decimalParts = new Intl.NumberFormat(locale, {...intlOptions, minimumFractionDigits: 2, maximumFractionDigits: 2}).formatToParts(0.001);\n\n let decimal = decimalParts.find(p => p.type === 'decimal')?.value;\n let group = allParts.find(p => p.type === 'group')?.value;\n\n // this set is also for a regex, it's all literals that might be in the string we want to eventually parse that\n // don't contribute to the numerical value\n let allPartsLiterals = allParts.filter(p => !nonLiteralParts.has(p.type)).map(p => escapeRegex(p.value));\n let pluralPartsLiterals = pluralParts.flatMap(p => p.filter(p => !nonLiteralParts.has(p.type)).map(p => escapeRegex(p.value)));\n let sortedLiterals = [...new Set([...allPartsLiterals, ...pluralPartsLiterals])].sort((a, b) => b.length - a.length);\n\n // Match both whitespace and formatting characters\n let literals = sortedLiterals.length === 0 ?\n new RegExp('\\\\p{White_Space}|\\\\p{Cf}', 'gu') :\n new RegExp(`${sortedLiterals.join('|')}|\\\\p{White_Space}|\\\\p{Cf}`, 'gu');\n\n // These are for replacing non-latn characters with the latn equivalent\n let numerals = [...new Intl.NumberFormat(intlOptions.locale, {useGrouping: false}).format(9876543210)].reverse();\n let indexes = new Map(numerals.map((d, i) => [d, i]));\n let numeral = new RegExp(`[${numerals.join('')}]`, 'g');\n let index = d => String(indexes.get(d));\n\n return {minusSign, plusSign, decimal, group, literals, numeral, numerals, index, noNumeralUnits};\n}\n\nfunction replaceAll(str: string, find: string | RegExp, replace: string) {\n if (str.replaceAll) {\n return str.replaceAll(find, replace);\n }\n\n return str.split(find).join(replace);\n}\n\nfunction escapeRegex(string: string) {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n"],"names":[],"version":3,"file":"NumberParser.cjs.map"}
1
+ {"mappings":"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","sources":["packages/@internationalized/number/src/NumberParser.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {NumberFormatter} from './NumberFormatter';\n\ninterface Symbols {\n minusSign?: string;\n plusSign?: string;\n decimal?: string;\n group?: string;\n literals: RegExp;\n numeral: RegExp;\n numerals: string[];\n index: (v: string) => string;\n noNumeralUnits: Array<{unit: string; value: number}>;\n}\n\nconst CURRENCY_SIGN_REGEX = new RegExp('^.*\\\\(.*\\\\).*$');\nconst NUMBERING_SYSTEMS = ['latn', 'arab', 'hanidec', 'deva', 'beng', 'fullwide'];\n\n/**\n * A NumberParser can be used to perform locale-aware parsing of numbers from Unicode strings,\n * as well as validation of partial user input. It automatically detects the numbering system\n * used in the input, and supports parsing decimals, percentages, currency values, and units\n * according to the locale.\n */\nexport class NumberParser {\n private locale: string;\n private options: Intl.NumberFormatOptions;\n\n constructor(locale: string, options: Intl.NumberFormatOptions = {}) {\n this.locale = locale;\n this.options = options;\n }\n\n /**\n * Parses the given string to a number. Returns NaN if a valid number could not be parsed.\n */\n parse(value: string): number {\n return getNumberParserImpl(this.locale, this.options, value).parse(value);\n }\n\n /**\n * Returns whether the given string could potentially be a valid number. This should be used to\n * validate user input as the user types. If a `minValue` or `maxValue` is provided, the validity\n * of the minus/plus sign characters can be checked.\n */\n isValidPartialNumber(value: string, minValue?: number, maxValue?: number): boolean {\n return getNumberParserImpl(this.locale, this.options, value).isValidPartialNumber(\n value,\n minValue,\n maxValue\n );\n }\n\n /**\n * Returns a numbering system for which the given string is valid in the current locale.\n * If no numbering system could be detected, the default numbering system for the current\n * locale is returned.\n */\n getNumberingSystem(value: string): string {\n return getNumberParserImpl(this.locale, this.options, value).options.numberingSystem;\n }\n}\n\nconst numberParserCache = new Map<string, NumberParserImpl>();\nfunction getNumberParserImpl(locale: string, options: Intl.NumberFormatOptions, value: string) {\n // First try the default numbering system for the provided locale\n let defaultParser = getCachedNumberParser(locale, options);\n\n // If that doesn't match, and the locale doesn't include a hard coded numbering system,\n // try each of the other supported numbering systems until we find one that matches.\n if (!locale.includes('-nu-') && !defaultParser.isValidPartialNumber(value)) {\n for (let numberingSystem of NUMBERING_SYSTEMS) {\n if (numberingSystem !== defaultParser.options.numberingSystem) {\n let parser = getCachedNumberParser(\n locale + (locale.includes('-u-') ? '-nu-' : '-u-nu-') + numberingSystem,\n options\n );\n if (parser.isValidPartialNumber(value)) {\n return parser;\n }\n }\n }\n }\n\n return defaultParser;\n}\n\nfunction getCachedNumberParser(locale: string, options: Intl.NumberFormatOptions) {\n let cacheKey =\n locale +\n (options\n ? Object.entries(options)\n .sort((a, b) => (a[0] < b[0] ? -1 : 1))\n .join()\n : '');\n let parser = numberParserCache.get(cacheKey);\n if (!parser) {\n parser = new NumberParserImpl(locale, options);\n numberParserCache.set(cacheKey, parser);\n }\n\n return parser;\n}\n\n// The actual number parser implementation. Instances of this class are cached\n// based on the locale, options, and detected numbering system.\nclass NumberParserImpl {\n formatter: Intl.NumberFormat;\n options: Intl.ResolvedNumberFormatOptions;\n symbols: Symbols;\n locale: string;\n\n constructor(locale: string, options: Intl.NumberFormatOptions = {}) {\n this.locale = locale;\n // see https://tc39.es/ecma402/#sec-setnfdigitoptions, when using roundingIncrement, the maximumFractionDigits and minimumFractionDigits must be equal\n // by default, they are 0 and 3 respectively, so we set them to 0 if neither are set\n if (options.roundingIncrement !== 1 && options.roundingIncrement != null) {\n if (options.maximumFractionDigits == null && options.minimumFractionDigits == null) {\n options.maximumFractionDigits = 0;\n options.minimumFractionDigits = 0;\n } else if (options.maximumFractionDigits == null) {\n options.maximumFractionDigits = options.minimumFractionDigits;\n } else if (options.minimumFractionDigits == null) {\n options.minimumFractionDigits = options.maximumFractionDigits;\n }\n // if both are specified, let the normal Range Error be thrown\n }\n this.formatter = new Intl.NumberFormat(locale, options);\n this.options = this.formatter.resolvedOptions();\n this.symbols = getSymbols(locale, this.formatter, this.options, options);\n if (\n this.options.style === 'percent' &&\n ((this.options.minimumFractionDigits ?? 0) > 18 ||\n (this.options.maximumFractionDigits ?? 0) > 18)\n ) {\n console.warn(\n 'NumberParser cannot handle percentages with greater than 18 decimal places, please reduce the number in your options.'\n );\n }\n }\n\n parse(value: string) {\n let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;\n // to parse the number, we need to remove anything that isn't actually part of the number, for example we want '-10.40' not '-10.40 USD'\n let fullySanitizedValue = this.sanitize(value);\n\n // Return NaN if there is a group symbol but useGrouping is false\n if (\n !isGroupSymbolAllowed &&\n this.symbols.group &&\n fullySanitizedValue.includes(this.symbols.group)\n ) {\n return NaN;\n } else if (this.symbols.group) {\n fullySanitizedValue = fullySanitizedValue.replaceAll(this.symbols.group!, '');\n }\n\n if (this.symbols.decimal) {\n fullySanitizedValue = fullySanitizedValue.replace(this.symbols.decimal!, '.');\n }\n if (this.symbols.minusSign) {\n fullySanitizedValue = fullySanitizedValue.replace(this.symbols.minusSign!, '-');\n }\n fullySanitizedValue = fullySanitizedValue.replace(this.symbols.numeral, this.symbols.index);\n\n if (this.options.style === 'percent') {\n // javascript is bad at dividing by 100 and maintaining the same significant figures, so perform it on the string before parsing\n let isNegative = fullySanitizedValue.indexOf('-');\n fullySanitizedValue = fullySanitizedValue.replace('-', '');\n fullySanitizedValue = fullySanitizedValue.replace('+', '');\n let index = fullySanitizedValue.indexOf('.');\n if (index === -1) {\n index = fullySanitizedValue.length;\n }\n fullySanitizedValue = fullySanitizedValue.replace('.', '');\n if (index - 2 === 0) {\n fullySanitizedValue = `0.${fullySanitizedValue}`;\n } else if (index - 2 === -1) {\n fullySanitizedValue = `0.0${fullySanitizedValue}`;\n } else if (index - 2 === -2) {\n fullySanitizedValue = '0.00';\n } else {\n fullySanitizedValue = `${fullySanitizedValue.slice(0, index - 2)}.${fullySanitizedValue.slice(index - 2)}`;\n }\n if (isNegative > -1) {\n fullySanitizedValue = `-${fullySanitizedValue}`;\n }\n }\n\n let newValue = fullySanitizedValue ? +fullySanitizedValue : NaN;\n if (isNaN(newValue)) {\n return NaN;\n }\n\n if (this.options.style === 'percent') {\n // extra step for rounding percents to what our formatter would output\n let options = {\n ...this.options,\n style: 'decimal' as const,\n minimumFractionDigits: Math.min((this.options.minimumFractionDigits ?? 0) + 2, 20),\n maximumFractionDigits: Math.min((this.options.maximumFractionDigits ?? 0) + 2, 20)\n };\n return new NumberParser(this.locale, options).parse(\n new NumberFormatter(this.locale, options).format(newValue)\n );\n }\n\n // accounting will always be stripped to a positive number, so if it's accounting and has a () around everything, then we need to make it negative again\n if (this.options.currencySign === 'accounting' && CURRENCY_SIGN_REGEX.test(value)) {\n newValue = -1 * newValue;\n }\n return newValue;\n }\n\n sanitize(value: string) {\n let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;\n // If the value is only a unit and it matches one of the formatted numbers where the value is part of the unit and doesn't have any numerals, then\n // return the known value for that case.\n if (\n this.symbols.noNumeralUnits.length > 0 &&\n this.symbols.noNumeralUnits.find(obj => obj.unit === value)\n ) {\n return this.symbols.noNumeralUnits.find(obj => obj.unit === value)!.value.toString();\n }\n\n value = value.replace(this.symbols.literals, '');\n\n // Replace the ASCII minus sign with the minus sign used in the current locale\n // so that both are allowed in case the user's keyboard doesn't have the locale's minus sign.\n if (this.symbols.minusSign) {\n value = value.replace('-', this.symbols.minusSign);\n }\n\n // In arab numeral system, their decimal character is 1643, but most keyboards don't type that\n // instead they use the , (44) character or apparently the (1548) character.\n if (this.options.numberingSystem === 'arab') {\n if (this.symbols.decimal) {\n value = replaceAll(value, ',', this.symbols.decimal);\n value = replaceAll(value, String.fromCharCode(1548), this.symbols.decimal);\n }\n if (this.symbols.group && isGroupSymbolAllowed) {\n value = replaceAll(value, '.', this.symbols.group);\n }\n }\n\n // In some locale styles, such as swiss currency, the group character can be a special single quote\n // that keyboards don't typically have. This expands the character to include the easier to type single quote.\n if (this.symbols.group === '’' && value.includes(\"'\") && isGroupSymbolAllowed) {\n value = replaceAll(value, \"'\", this.symbols.group);\n }\n\n // On newer ICU versions, the special single quote has been normalized, so we need to backport.\n if (this.symbols.group === \"'\" && value.includes('’') && isGroupSymbolAllowed) {\n value = replaceAll(value, '’', this.symbols.group);\n }\n\n // fr-FR group character is narrow non-breaking space, char code 8239 (U+202F), but that's not a key on the french keyboard,\n // so allow space and non-breaking space as a group char as well\n if (this.options.locale === 'fr-FR' && this.symbols.group && isGroupSymbolAllowed) {\n value = replaceAll(value, ' ', this.symbols.group);\n value = replaceAll(value, /\\u00A0/g, this.symbols.group);\n }\n\n return value;\n }\n\n isValidPartialNumber(\n value: string,\n minValue: number = -Infinity,\n maxValue: number = Infinity\n ): boolean {\n let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;\n value = this.sanitize(value);\n\n // Remove minus or plus sign, which must be at the start of the string.\n if (this.symbols.minusSign && value.startsWith(this.symbols.minusSign) && minValue < 0) {\n value = value.slice(this.symbols.minusSign.length);\n } else if (this.symbols.plusSign && value.startsWith(this.symbols.plusSign) && maxValue > 0) {\n value = value.slice(this.symbols.plusSign.length);\n }\n\n // Numbers that can't have any decimal values fail if a decimal character is typed\n if (\n this.symbols.decimal &&\n value.indexOf(this.symbols.decimal) > -1 &&\n this.options.maximumFractionDigits === 0\n ) {\n return false;\n }\n\n // Remove numerals, groups, and decimals\n if (this.symbols.group && isGroupSymbolAllowed) {\n value = replaceAll(value, this.symbols.group, '');\n }\n value = value.replace(this.symbols.numeral, '');\n if (this.symbols.decimal) {\n value = value.replace(this.symbols.decimal, '');\n }\n\n // The number is valid if there are no remaining characters\n return value.length === 0;\n }\n}\n\nconst nonLiteralParts = new Set([\n 'decimal',\n 'fraction',\n 'integer',\n 'minusSign',\n 'plusSign',\n 'group'\n]);\n\n// This list is derived from https://www.unicode.org/cldr/charts/49/supplemental/language_plural_rules.html#comparison and includes\n// all unique numbers which we need to check in order to determine all the plural forms for a given locale.\n// Run scripts/generateAllPlurals.mjs to generate this list.\nconst pluralNumbers = [0, 4, 2, 1, 11, 20, 3, 7, 100, 21, 0.1, 1.1];\n\nfunction getSymbols(\n locale: string,\n formatter: Intl.NumberFormat,\n intlOptions: Intl.ResolvedNumberFormatOptions,\n originalOptions: Intl.NumberFormatOptions\n): Symbols {\n // formatter needs access to all decimal places in order to generate the correct literal strings for the plural set\n let symbolFormatter = new Intl.NumberFormat(locale, {\n ...intlOptions,\n // Resets so we get the full range of symbols\n minimumSignificantDigits: 1,\n maximumSignificantDigits: 21,\n roundingIncrement: 1,\n roundingPriority: 'auto',\n roundingMode: 'halfExpand',\n useGrouping: true\n });\n // Note: some locale's don't add a group symbol until there is a ten thousands place\n let allParts = symbolFormatter.formatToParts(-10000.111);\n let posAllParts = symbolFormatter.formatToParts(10000.111);\n let pluralParts = pluralNumbers.map(n => symbolFormatter.formatToParts(n));\n // if the plural parts include a unit but no integer or fraction, then we need to add the unit to the special set\n let noNumeralUnits = pluralParts\n .map((p, i) => {\n let unit = p.find(p => p.type === 'unit');\n if (unit && !p.some(p => p.type === 'integer' || p.type === 'fraction')) {\n return {unit: unit.value, value: pluralNumbers[i]};\n }\n return null;\n })\n .filter(p => !!p);\n\n let minusSign = allParts.find(p => p.type === 'minusSign')?.value ?? '-';\n let plusSign = posAllParts.find(p => p.type === 'plusSign')?.value;\n\n // Safari does not support the signDisplay option, but our number parser polyfills it.\n // If no plus sign was returned, but the original options contained signDisplay, default to the '+' character.\n if (\n !plusSign &&\n (originalOptions?.signDisplay === 'exceptZero' || originalOptions?.signDisplay === 'always')\n ) {\n plusSign = '+';\n }\n\n // If maximumSignificantDigits is 1 (the minimum) then we won't get decimal characters out of the above formatters\n // Percent also defaults to 0 fractionDigits, so we need to make a new one that isn't percent to get an accurate decimal\n let decimalParts = new Intl.NumberFormat(locale, {\n ...intlOptions,\n minimumFractionDigits: 2,\n maximumFractionDigits: 2\n }).formatToParts(0.001);\n\n let decimal = decimalParts.find(p => p.type === 'decimal')?.value;\n let group = allParts.find(p => p.type === 'group')?.value;\n\n // this set is also for a regex, it's all literals that might be in the string we want to eventually parse that\n // don't contribute to the numerical value\n let allPartsLiterals = allParts\n .filter(p => !nonLiteralParts.has(p.type))\n .map(p => escapeRegex(p.value));\n let pluralPartsLiterals = pluralParts.flatMap(p =>\n p.filter(p => !nonLiteralParts.has(p.type)).map(p => escapeRegex(p.value))\n );\n let sortedLiterals = [...new Set([...allPartsLiterals, ...pluralPartsLiterals])].sort(\n (a, b) => b.length - a.length\n );\n\n // Match both whitespace and formatting characters\n let literals =\n sortedLiterals.length === 0\n ? new RegExp('\\\\p{White_Space}|\\\\p{Cf}', 'gu')\n : new RegExp(`${sortedLiterals.join('|')}|\\\\p{White_Space}|\\\\p{Cf}`, 'gu');\n\n // These are for replacing non-latn characters with the latn equivalent\n let numerals = [\n ...new Intl.NumberFormat(intlOptions.locale, {useGrouping: false}).format(9876543210)\n ].reverse();\n let indexes = new Map(numerals.map((d, i) => [d, i]));\n let numeral = new RegExp(`[${numerals.join('')}]`, 'g');\n let index = d => String(indexes.get(d));\n\n return {minusSign, plusSign, decimal, group, literals, numeral, numerals, index, noNumeralUnits};\n}\n\nfunction replaceAll(str: string, find: string | RegExp, replace: string) {\n if (str.replaceAll) {\n return str.replaceAll(find, replace);\n }\n\n return str.split(find).join(replace);\n}\n\nfunction escapeRegex(string: string) {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n"],"names":[],"version":3,"file":"NumberParser.cjs.map"}
@@ -133,6 +133,8 @@ class $8f9e7ac92b21e8dd$var$NumberParserImpl {
133
133
  // In some locale styles, such as swiss currency, the group character can be a special single quote
134
134
  // that keyboards don't typically have. This expands the character to include the easier to type single quote.
135
135
  if (this.symbols.group === "\u2019" && value.includes("'") && isGroupSymbolAllowed) value = $8f9e7ac92b21e8dd$var$replaceAll(value, "'", this.symbols.group);
136
+ // On newer ICU versions, the special single quote has been normalized, so we need to backport.
137
+ if (this.symbols.group === "'" && value.includes("\u2019") && isGroupSymbolAllowed) value = $8f9e7ac92b21e8dd$var$replaceAll(value, "\u2019", this.symbols.group);
136
138
  // fr-FR group character is narrow non-breaking space, char code 8239 (U+202F), but that's not a key on the french keyboard,
137
139
  // so allow space and non-breaking space as a group char as well
138
140
  if (this.options.locale === 'fr-FR' && this.symbols.group && isGroupSymbolAllowed) {
@@ -183,9 +185,9 @@ const $8f9e7ac92b21e8dd$var$nonLiteralParts = new Set([
183
185
  'plusSign',
184
186
  'group'
185
187
  ]);
186
- // This list is derived from https://www.unicode.org/cldr/charts/43/supplemental/language_plural_rules.html#comparison and includes
188
+ // This list is derived from https://www.unicode.org/cldr/charts/49/supplemental/language_plural_rules.html#comparison and includes
187
189
  // all unique numbers which we need to check in order to determine all the plural forms for a given locale.
188
- // See: https://github.com/adobe/react-spectrum/pull/5134/files#r1337037855 for used script
190
+ // Run scripts/generateAllPlurals.mjs to generate this list.
189
191
  const $8f9e7ac92b21e8dd$var$pluralNumbers = [
190
192
  0,
191
193
  4,
@@ -1 +1 @@
1
- {"mappings":"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","sources":["packages/@internationalized/number/src/NumberParser.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {NumberFormatter} from './NumberFormatter';\n\ninterface Symbols {\n minusSign?: string,\n plusSign?: string,\n decimal?: string,\n group?: string,\n literals: RegExp,\n numeral: RegExp,\n numerals: string[],\n index: (v: string) => string,\n noNumeralUnits: Array<{unit: string, value: number}>\n}\n\nconst CURRENCY_SIGN_REGEX = new RegExp('^.*\\\\(.*\\\\).*$');\nconst NUMBERING_SYSTEMS = ['latn', 'arab', 'hanidec', 'deva', 'beng', 'fullwide'];\n\n/**\n * A NumberParser can be used to perform locale-aware parsing of numbers from Unicode strings,\n * as well as validation of partial user input. It automatically detects the numbering system\n * used in the input, and supports parsing decimals, percentages, currency values, and units\n * according to the locale.\n */\nexport class NumberParser {\n private locale: string;\n private options: Intl.NumberFormatOptions;\n\n constructor(locale: string, options: Intl.NumberFormatOptions = {}) {\n this.locale = locale;\n this.options = options;\n }\n\n /**\n * Parses the given string to a number. Returns NaN if a valid number could not be parsed.\n */\n parse(value: string): number {\n return getNumberParserImpl(this.locale, this.options, value).parse(value);\n }\n\n /**\n * Returns whether the given string could potentially be a valid number. This should be used to\n * validate user input as the user types. If a `minValue` or `maxValue` is provided, the validity\n * of the minus/plus sign characters can be checked.\n */\n isValidPartialNumber(value: string, minValue?: number, maxValue?: number): boolean {\n return getNumberParserImpl(this.locale, this.options, value).isValidPartialNumber(value, minValue, maxValue);\n }\n\n /**\n * Returns a numbering system for which the given string is valid in the current locale.\n * If no numbering system could be detected, the default numbering system for the current\n * locale is returned.\n */\n getNumberingSystem(value: string): string {\n return getNumberParserImpl(this.locale, this.options, value).options.numberingSystem;\n }\n}\n\nconst numberParserCache = new Map<string, NumberParserImpl>();\nfunction getNumberParserImpl(locale: string, options: Intl.NumberFormatOptions, value: string) {\n // First try the default numbering system for the provided locale\n let defaultParser = getCachedNumberParser(locale, options);\n\n // If that doesn't match, and the locale doesn't include a hard coded numbering system,\n // try each of the other supported numbering systems until we find one that matches.\n if (!locale.includes('-nu-') && !defaultParser.isValidPartialNumber(value)) {\n for (let numberingSystem of NUMBERING_SYSTEMS) {\n if (numberingSystem !== defaultParser.options.numberingSystem) {\n let parser = getCachedNumberParser(locale + (locale.includes('-u-') ? '-nu-' : '-u-nu-') + numberingSystem, options);\n if (parser.isValidPartialNumber(value)) {\n return parser;\n }\n }\n }\n }\n\n return defaultParser;\n}\n\nfunction getCachedNumberParser(locale: string, options: Intl.NumberFormatOptions) {\n let cacheKey = locale + (options ? Object.entries(options).sort((a, b) => a[0] < b[0] ? -1 : 1).join() : '');\n let parser = numberParserCache.get(cacheKey);\n if (!parser) {\n parser = new NumberParserImpl(locale, options);\n numberParserCache.set(cacheKey, parser);\n }\n\n return parser;\n}\n\n// The actual number parser implementation. Instances of this class are cached\n// based on the locale, options, and detected numbering system.\nclass NumberParserImpl {\n formatter: Intl.NumberFormat;\n options: Intl.ResolvedNumberFormatOptions;\n symbols: Symbols;\n locale: string;\n\n constructor(locale: string, options: Intl.NumberFormatOptions = {}) {\n this.locale = locale;\n // see https://tc39.es/ecma402/#sec-setnfdigitoptions, when using roundingIncrement, the maximumFractionDigits and minimumFractionDigits must be equal\n // by default, they are 0 and 3 respectively, so we set them to 0 if neither are set\n if (options.roundingIncrement !== 1 && options.roundingIncrement != null) {\n if (options.maximumFractionDigits == null && options.minimumFractionDigits == null) {\n options.maximumFractionDigits = 0;\n options.minimumFractionDigits = 0;\n } else if (options.maximumFractionDigits == null) {\n options.maximumFractionDigits = options.minimumFractionDigits;\n } else if (options.minimumFractionDigits == null) {\n options.minimumFractionDigits = options.maximumFractionDigits;\n }\n // if both are specified, let the normal Range Error be thrown\n }\n this.formatter = new Intl.NumberFormat(locale, options);\n this.options = this.formatter.resolvedOptions();\n this.symbols = getSymbols(locale, this.formatter, this.options, options);\n if (this.options.style === 'percent' && ((this.options.minimumFractionDigits ?? 0) > 18 || (this.options.maximumFractionDigits ?? 0) > 18)) {\n console.warn('NumberParser cannot handle percentages with greater than 18 decimal places, please reduce the number in your options.');\n }\n }\n\n parse(value: string) {\n let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;\n // to parse the number, we need to remove anything that isn't actually part of the number, for example we want '-10.40' not '-10.40 USD'\n let fullySanitizedValue = this.sanitize(value);\n\n // Return NaN if there is a group symbol but useGrouping is false\n if (!isGroupSymbolAllowed && this.symbols.group && fullySanitizedValue.includes(this.symbols.group)) {\n return NaN;\n } else if (this.symbols.group) {\n fullySanitizedValue = fullySanitizedValue.replaceAll(this.symbols.group!, '');\n }\n\n if (this.symbols.decimal) {\n fullySanitizedValue = fullySanitizedValue.replace(this.symbols.decimal!, '.');\n }\n if (this.symbols.minusSign) {\n fullySanitizedValue = fullySanitizedValue.replace(this.symbols.minusSign!, '-');\n }\n fullySanitizedValue = fullySanitizedValue.replace(this.symbols.numeral, this.symbols.index);\n\n if (this.options.style === 'percent') {\n // javascript is bad at dividing by 100 and maintaining the same significant figures, so perform it on the string before parsing\n let isNegative = fullySanitizedValue.indexOf('-');\n fullySanitizedValue = fullySanitizedValue.replace('-', '');\n fullySanitizedValue = fullySanitizedValue.replace('+', '');\n let index = fullySanitizedValue.indexOf('.');\n if (index === -1) {\n index = fullySanitizedValue.length;\n }\n fullySanitizedValue = fullySanitizedValue.replace('.', '');\n if (index - 2 === 0) {\n fullySanitizedValue = `0.${fullySanitizedValue}`;\n } else if (index - 2 === -1) {\n fullySanitizedValue = `0.0${fullySanitizedValue}`;\n } else if (index - 2 === -2) {\n fullySanitizedValue = '0.00';\n } else {\n fullySanitizedValue = `${fullySanitizedValue.slice(0, index - 2)}.${fullySanitizedValue.slice(index - 2)}`;\n }\n if (isNegative > -1) {\n fullySanitizedValue = `-${fullySanitizedValue}`;\n }\n }\n\n let newValue = fullySanitizedValue ? +fullySanitizedValue : NaN;\n if (isNaN(newValue)) {\n return NaN;\n }\n\n if (this.options.style === 'percent') {\n // extra step for rounding percents to what our formatter would output\n let options = {\n ...this.options,\n style: 'decimal' as const,\n minimumFractionDigits: Math.min((this.options.minimumFractionDigits ?? 0) + 2, 20),\n maximumFractionDigits: Math.min((this.options.maximumFractionDigits ?? 0) + 2, 20)\n };\n return (new NumberParser(this.locale, options)).parse(new NumberFormatter(this.locale, options).format(newValue));\n }\n\n // accounting will always be stripped to a positive number, so if it's accounting and has a () around everything, then we need to make it negative again\n if (this.options.currencySign === 'accounting' && CURRENCY_SIGN_REGEX.test(value)) {\n newValue = -1 * newValue;\n }\n return newValue;\n }\n\n sanitize(value: string) {\n let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;\n // If the value is only a unit and it matches one of the formatted numbers where the value is part of the unit and doesn't have any numerals, then\n // return the known value for that case.\n if (this.symbols.noNumeralUnits.length > 0 && this.symbols.noNumeralUnits.find(obj => obj.unit === value)) {\n return this.symbols.noNumeralUnits.find(obj => obj.unit === value)!.value.toString();\n }\n\n value = value.replace(this.symbols.literals, '');\n\n // Replace the ASCII minus sign with the minus sign used in the current locale\n // so that both are allowed in case the user's keyboard doesn't have the locale's minus sign.\n if (this.symbols.minusSign) {\n value = value.replace('-', this.symbols.minusSign);\n }\n\n // In arab numeral system, their decimal character is 1643, but most keyboards don't type that\n // instead they use the , (44) character or apparently the (1548) character.\n if (this.options.numberingSystem === 'arab') {\n if (this.symbols.decimal) {\n value = replaceAll(value, ',', this.symbols.decimal);\n value = replaceAll(value, String.fromCharCode(1548), this.symbols.decimal);\n }\n if (this.symbols.group && isGroupSymbolAllowed) {\n value = replaceAll(value, '.', this.symbols.group);\n }\n }\n\n // In some locale styles, such as swiss currency, the group character can be a special single quote\n // that keyboards don't typically have. This expands the character to include the easier to type single quote.\n if (this.symbols.group === '’' && value.includes(\"'\") && isGroupSymbolAllowed) {\n value = replaceAll(value, \"'\", this.symbols.group);\n }\n\n // fr-FR group character is narrow non-breaking space, char code 8239 (U+202F), but that's not a key on the french keyboard,\n // so allow space and non-breaking space as a group char as well\n if (this.options.locale === 'fr-FR' && this.symbols.group && isGroupSymbolAllowed) {\n value = replaceAll(value, ' ', this.symbols.group);\n value = replaceAll(value, /\\u00A0/g, this.symbols.group);\n }\n\n return value;\n }\n\n isValidPartialNumber(value: string, minValue: number = -Infinity, maxValue: number = Infinity): boolean {\n let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;\n value = this.sanitize(value);\n\n // Remove minus or plus sign, which must be at the start of the string.\n if (this.symbols.minusSign && value.startsWith(this.symbols.minusSign) && minValue < 0) {\n value = value.slice(this.symbols.minusSign.length);\n } else if (this.symbols.plusSign && value.startsWith(this.symbols.plusSign) && maxValue > 0) {\n value = value.slice(this.symbols.plusSign.length);\n }\n\n // Numbers that can't have any decimal values fail if a decimal character is typed\n if (this.symbols.decimal && value.indexOf(this.symbols.decimal) > -1 && this.options.maximumFractionDigits === 0) {\n return false;\n }\n\n // Remove numerals, groups, and decimals\n if (this.symbols.group && isGroupSymbolAllowed) {\n value = replaceAll(value, this.symbols.group, '');\n }\n value = value.replace(this.symbols.numeral, '');\n if (this.symbols.decimal) {\n value = value.replace(this.symbols.decimal, '');\n }\n\n // The number is valid if there are no remaining characters\n return value.length === 0;\n }\n}\n\nconst nonLiteralParts = new Set(['decimal', 'fraction', 'integer', 'minusSign', 'plusSign', 'group']);\n\n// This list is derived from https://www.unicode.org/cldr/charts/43/supplemental/language_plural_rules.html#comparison and includes\n// all unique numbers which we need to check in order to determine all the plural forms for a given locale.\n// See: https://github.com/adobe/react-spectrum/pull/5134/files#r1337037855 for used script\nconst pluralNumbers = [\n 0, 4, 2, 1, 11, 20, 3, 7, 100, 21, 0.1, 1.1\n];\n\nfunction getSymbols(locale: string, formatter: Intl.NumberFormat, intlOptions: Intl.ResolvedNumberFormatOptions, originalOptions: Intl.NumberFormatOptions): Symbols {\n // formatter needs access to all decimal places in order to generate the correct literal strings for the plural set\n let symbolFormatter = new Intl.NumberFormat(locale, {...intlOptions,\n // Resets so we get the full range of symbols\n minimumSignificantDigits: 1,\n maximumSignificantDigits: 21,\n roundingIncrement: 1,\n roundingPriority: 'auto',\n roundingMode: 'halfExpand',\n useGrouping: true\n });\n // Note: some locale's don't add a group symbol until there is a ten thousands place\n let allParts = symbolFormatter.formatToParts(-10000.111);\n let posAllParts = symbolFormatter.formatToParts(10000.111);\n let pluralParts = pluralNumbers.map(n => symbolFormatter.formatToParts(n));\n // if the plural parts include a unit but no integer or fraction, then we need to add the unit to the special set\n let noNumeralUnits = pluralParts.map((p, i) => {\n let unit = p.find(p => p.type === 'unit');\n if (unit && !p.some(p => p.type === 'integer' || p.type === 'fraction')) {\n return {unit: unit.value, value: pluralNumbers[i]};\n }\n return null;\n }).filter(p => !!p);\n\n let minusSign = allParts.find(p => p.type === 'minusSign')?.value ?? '-';\n let plusSign = posAllParts.find(p => p.type === 'plusSign')?.value;\n\n // Safari does not support the signDisplay option, but our number parser polyfills it.\n // If no plus sign was returned, but the original options contained signDisplay, default to the '+' character.\n if (!plusSign && (originalOptions?.signDisplay === 'exceptZero' || originalOptions?.signDisplay === 'always')) {\n plusSign = '+';\n }\n\n // If maximumSignificantDigits is 1 (the minimum) then we won't get decimal characters out of the above formatters\n // Percent also defaults to 0 fractionDigits, so we need to make a new one that isn't percent to get an accurate decimal\n let decimalParts = new Intl.NumberFormat(locale, {...intlOptions, minimumFractionDigits: 2, maximumFractionDigits: 2}).formatToParts(0.001);\n\n let decimal = decimalParts.find(p => p.type === 'decimal')?.value;\n let group = allParts.find(p => p.type === 'group')?.value;\n\n // this set is also for a regex, it's all literals that might be in the string we want to eventually parse that\n // don't contribute to the numerical value\n let allPartsLiterals = allParts.filter(p => !nonLiteralParts.has(p.type)).map(p => escapeRegex(p.value));\n let pluralPartsLiterals = pluralParts.flatMap(p => p.filter(p => !nonLiteralParts.has(p.type)).map(p => escapeRegex(p.value)));\n let sortedLiterals = [...new Set([...allPartsLiterals, ...pluralPartsLiterals])].sort((a, b) => b.length - a.length);\n\n // Match both whitespace and formatting characters\n let literals = sortedLiterals.length === 0 ?\n new RegExp('\\\\p{White_Space}|\\\\p{Cf}', 'gu') :\n new RegExp(`${sortedLiterals.join('|')}|\\\\p{White_Space}|\\\\p{Cf}`, 'gu');\n\n // These are for replacing non-latn characters with the latn equivalent\n let numerals = [...new Intl.NumberFormat(intlOptions.locale, {useGrouping: false}).format(9876543210)].reverse();\n let indexes = new Map(numerals.map((d, i) => [d, i]));\n let numeral = new RegExp(`[${numerals.join('')}]`, 'g');\n let index = d => String(indexes.get(d));\n\n return {minusSign, plusSign, decimal, group, literals, numeral, numerals, index, noNumeralUnits};\n}\n\nfunction replaceAll(str: string, find: string | RegExp, replace: string) {\n if (str.replaceAll) {\n return str.replaceAll(find, replace);\n }\n\n return str.split(find).join(replace);\n}\n\nfunction escapeRegex(string: string) {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n"],"names":[],"version":3,"file":"NumberParser.js.map"}
1
+ {"mappings":"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","sources":["packages/@internationalized/number/src/NumberParser.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {NumberFormatter} from './NumberFormatter';\n\ninterface Symbols {\n minusSign?: string;\n plusSign?: string;\n decimal?: string;\n group?: string;\n literals: RegExp;\n numeral: RegExp;\n numerals: string[];\n index: (v: string) => string;\n noNumeralUnits: Array<{unit: string; value: number}>;\n}\n\nconst CURRENCY_SIGN_REGEX = new RegExp('^.*\\\\(.*\\\\).*$');\nconst NUMBERING_SYSTEMS = ['latn', 'arab', 'hanidec', 'deva', 'beng', 'fullwide'];\n\n/**\n * A NumberParser can be used to perform locale-aware parsing of numbers from Unicode strings,\n * as well as validation of partial user input. It automatically detects the numbering system\n * used in the input, and supports parsing decimals, percentages, currency values, and units\n * according to the locale.\n */\nexport class NumberParser {\n private locale: string;\n private options: Intl.NumberFormatOptions;\n\n constructor(locale: string, options: Intl.NumberFormatOptions = {}) {\n this.locale = locale;\n this.options = options;\n }\n\n /**\n * Parses the given string to a number. Returns NaN if a valid number could not be parsed.\n */\n parse(value: string): number {\n return getNumberParserImpl(this.locale, this.options, value).parse(value);\n }\n\n /**\n * Returns whether the given string could potentially be a valid number. This should be used to\n * validate user input as the user types. If a `minValue` or `maxValue` is provided, the validity\n * of the minus/plus sign characters can be checked.\n */\n isValidPartialNumber(value: string, minValue?: number, maxValue?: number): boolean {\n return getNumberParserImpl(this.locale, this.options, value).isValidPartialNumber(\n value,\n minValue,\n maxValue\n );\n }\n\n /**\n * Returns a numbering system for which the given string is valid in the current locale.\n * If no numbering system could be detected, the default numbering system for the current\n * locale is returned.\n */\n getNumberingSystem(value: string): string {\n return getNumberParserImpl(this.locale, this.options, value).options.numberingSystem;\n }\n}\n\nconst numberParserCache = new Map<string, NumberParserImpl>();\nfunction getNumberParserImpl(locale: string, options: Intl.NumberFormatOptions, value: string) {\n // First try the default numbering system for the provided locale\n let defaultParser = getCachedNumberParser(locale, options);\n\n // If that doesn't match, and the locale doesn't include a hard coded numbering system,\n // try each of the other supported numbering systems until we find one that matches.\n if (!locale.includes('-nu-') && !defaultParser.isValidPartialNumber(value)) {\n for (let numberingSystem of NUMBERING_SYSTEMS) {\n if (numberingSystem !== defaultParser.options.numberingSystem) {\n let parser = getCachedNumberParser(\n locale + (locale.includes('-u-') ? '-nu-' : '-u-nu-') + numberingSystem,\n options\n );\n if (parser.isValidPartialNumber(value)) {\n return parser;\n }\n }\n }\n }\n\n return defaultParser;\n}\n\nfunction getCachedNumberParser(locale: string, options: Intl.NumberFormatOptions) {\n let cacheKey =\n locale +\n (options\n ? Object.entries(options)\n .sort((a, b) => (a[0] < b[0] ? -1 : 1))\n .join()\n : '');\n let parser = numberParserCache.get(cacheKey);\n if (!parser) {\n parser = new NumberParserImpl(locale, options);\n numberParserCache.set(cacheKey, parser);\n }\n\n return parser;\n}\n\n// The actual number parser implementation. Instances of this class are cached\n// based on the locale, options, and detected numbering system.\nclass NumberParserImpl {\n formatter: Intl.NumberFormat;\n options: Intl.ResolvedNumberFormatOptions;\n symbols: Symbols;\n locale: string;\n\n constructor(locale: string, options: Intl.NumberFormatOptions = {}) {\n this.locale = locale;\n // see https://tc39.es/ecma402/#sec-setnfdigitoptions, when using roundingIncrement, the maximumFractionDigits and minimumFractionDigits must be equal\n // by default, they are 0 and 3 respectively, so we set them to 0 if neither are set\n if (options.roundingIncrement !== 1 && options.roundingIncrement != null) {\n if (options.maximumFractionDigits == null && options.minimumFractionDigits == null) {\n options.maximumFractionDigits = 0;\n options.minimumFractionDigits = 0;\n } else if (options.maximumFractionDigits == null) {\n options.maximumFractionDigits = options.minimumFractionDigits;\n } else if (options.minimumFractionDigits == null) {\n options.minimumFractionDigits = options.maximumFractionDigits;\n }\n // if both are specified, let the normal Range Error be thrown\n }\n this.formatter = new Intl.NumberFormat(locale, options);\n this.options = this.formatter.resolvedOptions();\n this.symbols = getSymbols(locale, this.formatter, this.options, options);\n if (\n this.options.style === 'percent' &&\n ((this.options.minimumFractionDigits ?? 0) > 18 ||\n (this.options.maximumFractionDigits ?? 0) > 18)\n ) {\n console.warn(\n 'NumberParser cannot handle percentages with greater than 18 decimal places, please reduce the number in your options.'\n );\n }\n }\n\n parse(value: string) {\n let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;\n // to parse the number, we need to remove anything that isn't actually part of the number, for example we want '-10.40' not '-10.40 USD'\n let fullySanitizedValue = this.sanitize(value);\n\n // Return NaN if there is a group symbol but useGrouping is false\n if (\n !isGroupSymbolAllowed &&\n this.symbols.group &&\n fullySanitizedValue.includes(this.symbols.group)\n ) {\n return NaN;\n } else if (this.symbols.group) {\n fullySanitizedValue = fullySanitizedValue.replaceAll(this.symbols.group!, '');\n }\n\n if (this.symbols.decimal) {\n fullySanitizedValue = fullySanitizedValue.replace(this.symbols.decimal!, '.');\n }\n if (this.symbols.minusSign) {\n fullySanitizedValue = fullySanitizedValue.replace(this.symbols.minusSign!, '-');\n }\n fullySanitizedValue = fullySanitizedValue.replace(this.symbols.numeral, this.symbols.index);\n\n if (this.options.style === 'percent') {\n // javascript is bad at dividing by 100 and maintaining the same significant figures, so perform it on the string before parsing\n let isNegative = fullySanitizedValue.indexOf('-');\n fullySanitizedValue = fullySanitizedValue.replace('-', '');\n fullySanitizedValue = fullySanitizedValue.replace('+', '');\n let index = fullySanitizedValue.indexOf('.');\n if (index === -1) {\n index = fullySanitizedValue.length;\n }\n fullySanitizedValue = fullySanitizedValue.replace('.', '');\n if (index - 2 === 0) {\n fullySanitizedValue = `0.${fullySanitizedValue}`;\n } else if (index - 2 === -1) {\n fullySanitizedValue = `0.0${fullySanitizedValue}`;\n } else if (index - 2 === -2) {\n fullySanitizedValue = '0.00';\n } else {\n fullySanitizedValue = `${fullySanitizedValue.slice(0, index - 2)}.${fullySanitizedValue.slice(index - 2)}`;\n }\n if (isNegative > -1) {\n fullySanitizedValue = `-${fullySanitizedValue}`;\n }\n }\n\n let newValue = fullySanitizedValue ? +fullySanitizedValue : NaN;\n if (isNaN(newValue)) {\n return NaN;\n }\n\n if (this.options.style === 'percent') {\n // extra step for rounding percents to what our formatter would output\n let options = {\n ...this.options,\n style: 'decimal' as const,\n minimumFractionDigits: Math.min((this.options.minimumFractionDigits ?? 0) + 2, 20),\n maximumFractionDigits: Math.min((this.options.maximumFractionDigits ?? 0) + 2, 20)\n };\n return new NumberParser(this.locale, options).parse(\n new NumberFormatter(this.locale, options).format(newValue)\n );\n }\n\n // accounting will always be stripped to a positive number, so if it's accounting and has a () around everything, then we need to make it negative again\n if (this.options.currencySign === 'accounting' && CURRENCY_SIGN_REGEX.test(value)) {\n newValue = -1 * newValue;\n }\n return newValue;\n }\n\n sanitize(value: string) {\n let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;\n // If the value is only a unit and it matches one of the formatted numbers where the value is part of the unit and doesn't have any numerals, then\n // return the known value for that case.\n if (\n this.symbols.noNumeralUnits.length > 0 &&\n this.symbols.noNumeralUnits.find(obj => obj.unit === value)\n ) {\n return this.symbols.noNumeralUnits.find(obj => obj.unit === value)!.value.toString();\n }\n\n value = value.replace(this.symbols.literals, '');\n\n // Replace the ASCII minus sign with the minus sign used in the current locale\n // so that both are allowed in case the user's keyboard doesn't have the locale's minus sign.\n if (this.symbols.minusSign) {\n value = value.replace('-', this.symbols.minusSign);\n }\n\n // In arab numeral system, their decimal character is 1643, but most keyboards don't type that\n // instead they use the , (44) character or apparently the (1548) character.\n if (this.options.numberingSystem === 'arab') {\n if (this.symbols.decimal) {\n value = replaceAll(value, ',', this.symbols.decimal);\n value = replaceAll(value, String.fromCharCode(1548), this.symbols.decimal);\n }\n if (this.symbols.group && isGroupSymbolAllowed) {\n value = replaceAll(value, '.', this.symbols.group);\n }\n }\n\n // In some locale styles, such as swiss currency, the group character can be a special single quote\n // that keyboards don't typically have. This expands the character to include the easier to type single quote.\n if (this.symbols.group === '’' && value.includes(\"'\") && isGroupSymbolAllowed) {\n value = replaceAll(value, \"'\", this.symbols.group);\n }\n\n // On newer ICU versions, the special single quote has been normalized, so we need to backport.\n if (this.symbols.group === \"'\" && value.includes('’') && isGroupSymbolAllowed) {\n value = replaceAll(value, '’', this.symbols.group);\n }\n\n // fr-FR group character is narrow non-breaking space, char code 8239 (U+202F), but that's not a key on the french keyboard,\n // so allow space and non-breaking space as a group char as well\n if (this.options.locale === 'fr-FR' && this.symbols.group && isGroupSymbolAllowed) {\n value = replaceAll(value, ' ', this.symbols.group);\n value = replaceAll(value, /\\u00A0/g, this.symbols.group);\n }\n\n return value;\n }\n\n isValidPartialNumber(\n value: string,\n minValue: number = -Infinity,\n maxValue: number = Infinity\n ): boolean {\n let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;\n value = this.sanitize(value);\n\n // Remove minus or plus sign, which must be at the start of the string.\n if (this.symbols.minusSign && value.startsWith(this.symbols.minusSign) && minValue < 0) {\n value = value.slice(this.symbols.minusSign.length);\n } else if (this.symbols.plusSign && value.startsWith(this.symbols.plusSign) && maxValue > 0) {\n value = value.slice(this.symbols.plusSign.length);\n }\n\n // Numbers that can't have any decimal values fail if a decimal character is typed\n if (\n this.symbols.decimal &&\n value.indexOf(this.symbols.decimal) > -1 &&\n this.options.maximumFractionDigits === 0\n ) {\n return false;\n }\n\n // Remove numerals, groups, and decimals\n if (this.symbols.group && isGroupSymbolAllowed) {\n value = replaceAll(value, this.symbols.group, '');\n }\n value = value.replace(this.symbols.numeral, '');\n if (this.symbols.decimal) {\n value = value.replace(this.symbols.decimal, '');\n }\n\n // The number is valid if there are no remaining characters\n return value.length === 0;\n }\n}\n\nconst nonLiteralParts = new Set([\n 'decimal',\n 'fraction',\n 'integer',\n 'minusSign',\n 'plusSign',\n 'group'\n]);\n\n// This list is derived from https://www.unicode.org/cldr/charts/49/supplemental/language_plural_rules.html#comparison and includes\n// all unique numbers which we need to check in order to determine all the plural forms for a given locale.\n// Run scripts/generateAllPlurals.mjs to generate this list.\nconst pluralNumbers = [0, 4, 2, 1, 11, 20, 3, 7, 100, 21, 0.1, 1.1];\n\nfunction getSymbols(\n locale: string,\n formatter: Intl.NumberFormat,\n intlOptions: Intl.ResolvedNumberFormatOptions,\n originalOptions: Intl.NumberFormatOptions\n): Symbols {\n // formatter needs access to all decimal places in order to generate the correct literal strings for the plural set\n let symbolFormatter = new Intl.NumberFormat(locale, {\n ...intlOptions,\n // Resets so we get the full range of symbols\n minimumSignificantDigits: 1,\n maximumSignificantDigits: 21,\n roundingIncrement: 1,\n roundingPriority: 'auto',\n roundingMode: 'halfExpand',\n useGrouping: true\n });\n // Note: some locale's don't add a group symbol until there is a ten thousands place\n let allParts = symbolFormatter.formatToParts(-10000.111);\n let posAllParts = symbolFormatter.formatToParts(10000.111);\n let pluralParts = pluralNumbers.map(n => symbolFormatter.formatToParts(n));\n // if the plural parts include a unit but no integer or fraction, then we need to add the unit to the special set\n let noNumeralUnits = pluralParts\n .map((p, i) => {\n let unit = p.find(p => p.type === 'unit');\n if (unit && !p.some(p => p.type === 'integer' || p.type === 'fraction')) {\n return {unit: unit.value, value: pluralNumbers[i]};\n }\n return null;\n })\n .filter(p => !!p);\n\n let minusSign = allParts.find(p => p.type === 'minusSign')?.value ?? '-';\n let plusSign = posAllParts.find(p => p.type === 'plusSign')?.value;\n\n // Safari does not support the signDisplay option, but our number parser polyfills it.\n // If no plus sign was returned, but the original options contained signDisplay, default to the '+' character.\n if (\n !plusSign &&\n (originalOptions?.signDisplay === 'exceptZero' || originalOptions?.signDisplay === 'always')\n ) {\n plusSign = '+';\n }\n\n // If maximumSignificantDigits is 1 (the minimum) then we won't get decimal characters out of the above formatters\n // Percent also defaults to 0 fractionDigits, so we need to make a new one that isn't percent to get an accurate decimal\n let decimalParts = new Intl.NumberFormat(locale, {\n ...intlOptions,\n minimumFractionDigits: 2,\n maximumFractionDigits: 2\n }).formatToParts(0.001);\n\n let decimal = decimalParts.find(p => p.type === 'decimal')?.value;\n let group = allParts.find(p => p.type === 'group')?.value;\n\n // this set is also for a regex, it's all literals that might be in the string we want to eventually parse that\n // don't contribute to the numerical value\n let allPartsLiterals = allParts\n .filter(p => !nonLiteralParts.has(p.type))\n .map(p => escapeRegex(p.value));\n let pluralPartsLiterals = pluralParts.flatMap(p =>\n p.filter(p => !nonLiteralParts.has(p.type)).map(p => escapeRegex(p.value))\n );\n let sortedLiterals = [...new Set([...allPartsLiterals, ...pluralPartsLiterals])].sort(\n (a, b) => b.length - a.length\n );\n\n // Match both whitespace and formatting characters\n let literals =\n sortedLiterals.length === 0\n ? new RegExp('\\\\p{White_Space}|\\\\p{Cf}', 'gu')\n : new RegExp(`${sortedLiterals.join('|')}|\\\\p{White_Space}|\\\\p{Cf}`, 'gu');\n\n // These are for replacing non-latn characters with the latn equivalent\n let numerals = [\n ...new Intl.NumberFormat(intlOptions.locale, {useGrouping: false}).format(9876543210)\n ].reverse();\n let indexes = new Map(numerals.map((d, i) => [d, i]));\n let numeral = new RegExp(`[${numerals.join('')}]`, 'g');\n let index = d => String(indexes.get(d));\n\n return {minusSign, plusSign, decimal, group, literals, numeral, numerals, index, noNumeralUnits};\n}\n\nfunction replaceAll(str: string, find: string | RegExp, replace: string) {\n if (str.replaceAll) {\n return str.replaceAll(find, replace);\n }\n\n return str.split(find).join(replace);\n}\n\nfunction escapeRegex(string: string) {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n"],"names":[],"version":3,"file":"NumberParser.js.map"}
@@ -149,6 +149,8 @@ class $eb76cf4feb040f77$var$NumberParserImpl {
149
149
  // In some locale styles, such as swiss currency, the group character can be a special single quote
150
150
  // that keyboards don't typically have. This expands the character to include the easier to type single quote.
151
151
  if (this.symbols.group === "\u2019" && value.includes("'") && isGroupSymbolAllowed) value = $eb76cf4feb040f77$var$replaceAll(value, "'", this.symbols.group);
152
+ // On newer ICU versions, the special single quote has been normalized, so we need to backport.
153
+ if (this.symbols.group === "'" && value.includes("\u2019") && isGroupSymbolAllowed) value = $eb76cf4feb040f77$var$replaceAll(value, "\u2019", this.symbols.group);
152
154
  // fr-FR group character is narrow non-breaking space, char code 8239 (U+202F), but that's not a key on the french keyboard,
153
155
  // so allow space and non-breaking space as a group char as well
154
156
  if (this.options.locale === 'fr-FR' && this.symbols.group && isGroupSymbolAllowed) {
@@ -181,9 +183,9 @@ const $eb76cf4feb040f77$var$nonLiteralParts = new Set([
181
183
  'plusSign',
182
184
  'group'
183
185
  ]);
184
- // This list is derived from https://www.unicode.org/cldr/charts/43/supplemental/language_plural_rules.html#comparison and includes
186
+ // This list is derived from https://www.unicode.org/cldr/charts/49/supplemental/language_plural_rules.html#comparison and includes
185
187
  // all unique numbers which we need to check in order to determine all the plural forms for a given locale.
186
- // See: https://github.com/adobe/react-spectrum/pull/5134/files#r1337037855 for used script
188
+ // Run scripts/generateAllPlurals.mjs to generate this list.
187
189
  const $eb76cf4feb040f77$var$pluralNumbers = [
188
190
  0,
189
191
  4,
@@ -1 +1 @@
1
- {"mappings":"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","sources":["packages/@internationalized/number/src/NumberParser.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {NumberFormatter} from './NumberFormatter';\n\ninterface Symbols {\n minusSign?: string,\n plusSign?: string,\n decimal?: string,\n group?: string,\n literals: RegExp,\n numeral: RegExp,\n numerals: string[],\n index: (v: string) => string,\n noNumeralUnits: Array<{unit: string, value: number}>\n}\n\nconst CURRENCY_SIGN_REGEX = new RegExp('^.*\\\\(.*\\\\).*$');\nconst NUMBERING_SYSTEMS = ['latn', 'arab', 'hanidec', 'deva', 'beng', 'fullwide'];\n\n/**\n * A NumberParser can be used to perform locale-aware parsing of numbers from Unicode strings,\n * as well as validation of partial user input. It automatically detects the numbering system\n * used in the input, and supports parsing decimals, percentages, currency values, and units\n * according to the locale.\n */\nexport class NumberParser {\n private locale: string;\n private options: Intl.NumberFormatOptions;\n\n constructor(locale: string, options: Intl.NumberFormatOptions = {}) {\n this.locale = locale;\n this.options = options;\n }\n\n /**\n * Parses the given string to a number. Returns NaN if a valid number could not be parsed.\n */\n parse(value: string): number {\n return getNumberParserImpl(this.locale, this.options, value).parse(value);\n }\n\n /**\n * Returns whether the given string could potentially be a valid number. This should be used to\n * validate user input as the user types. If a `minValue` or `maxValue` is provided, the validity\n * of the minus/plus sign characters can be checked.\n */\n isValidPartialNumber(value: string, minValue?: number, maxValue?: number): boolean {\n return getNumberParserImpl(this.locale, this.options, value).isValidPartialNumber(value, minValue, maxValue);\n }\n\n /**\n * Returns a numbering system for which the given string is valid in the current locale.\n * If no numbering system could be detected, the default numbering system for the current\n * locale is returned.\n */\n getNumberingSystem(value: string): string {\n return getNumberParserImpl(this.locale, this.options, value).options.numberingSystem;\n }\n}\n\nconst numberParserCache = new Map<string, NumberParserImpl>();\nfunction getNumberParserImpl(locale: string, options: Intl.NumberFormatOptions, value: string) {\n // First try the default numbering system for the provided locale\n let defaultParser = getCachedNumberParser(locale, options);\n\n // If that doesn't match, and the locale doesn't include a hard coded numbering system,\n // try each of the other supported numbering systems until we find one that matches.\n if (!locale.includes('-nu-') && !defaultParser.isValidPartialNumber(value)) {\n for (let numberingSystem of NUMBERING_SYSTEMS) {\n if (numberingSystem !== defaultParser.options.numberingSystem) {\n let parser = getCachedNumberParser(locale + (locale.includes('-u-') ? '-nu-' : '-u-nu-') + numberingSystem, options);\n if (parser.isValidPartialNumber(value)) {\n return parser;\n }\n }\n }\n }\n\n return defaultParser;\n}\n\nfunction getCachedNumberParser(locale: string, options: Intl.NumberFormatOptions) {\n let cacheKey = locale + (options ? Object.entries(options).sort((a, b) => a[0] < b[0] ? -1 : 1).join() : '');\n let parser = numberParserCache.get(cacheKey);\n if (!parser) {\n parser = new NumberParserImpl(locale, options);\n numberParserCache.set(cacheKey, parser);\n }\n\n return parser;\n}\n\n// The actual number parser implementation. Instances of this class are cached\n// based on the locale, options, and detected numbering system.\nclass NumberParserImpl {\n formatter: Intl.NumberFormat;\n options: Intl.ResolvedNumberFormatOptions;\n symbols: Symbols;\n locale: string;\n\n constructor(locale: string, options: Intl.NumberFormatOptions = {}) {\n this.locale = locale;\n // see https://tc39.es/ecma402/#sec-setnfdigitoptions, when using roundingIncrement, the maximumFractionDigits and minimumFractionDigits must be equal\n // by default, they are 0 and 3 respectively, so we set them to 0 if neither are set\n if (options.roundingIncrement !== 1 && options.roundingIncrement != null) {\n if (options.maximumFractionDigits == null && options.minimumFractionDigits == null) {\n options.maximumFractionDigits = 0;\n options.minimumFractionDigits = 0;\n } else if (options.maximumFractionDigits == null) {\n options.maximumFractionDigits = options.minimumFractionDigits;\n } else if (options.minimumFractionDigits == null) {\n options.minimumFractionDigits = options.maximumFractionDigits;\n }\n // if both are specified, let the normal Range Error be thrown\n }\n this.formatter = new Intl.NumberFormat(locale, options);\n this.options = this.formatter.resolvedOptions();\n this.symbols = getSymbols(locale, this.formatter, this.options, options);\n if (this.options.style === 'percent' && ((this.options.minimumFractionDigits ?? 0) > 18 || (this.options.maximumFractionDigits ?? 0) > 18)) {\n console.warn('NumberParser cannot handle percentages with greater than 18 decimal places, please reduce the number in your options.');\n }\n }\n\n parse(value: string) {\n let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;\n // to parse the number, we need to remove anything that isn't actually part of the number, for example we want '-10.40' not '-10.40 USD'\n let fullySanitizedValue = this.sanitize(value);\n\n // Return NaN if there is a group symbol but useGrouping is false\n if (!isGroupSymbolAllowed && this.symbols.group && fullySanitizedValue.includes(this.symbols.group)) {\n return NaN;\n } else if (this.symbols.group) {\n fullySanitizedValue = fullySanitizedValue.replaceAll(this.symbols.group!, '');\n }\n\n if (this.symbols.decimal) {\n fullySanitizedValue = fullySanitizedValue.replace(this.symbols.decimal!, '.');\n }\n if (this.symbols.minusSign) {\n fullySanitizedValue = fullySanitizedValue.replace(this.symbols.minusSign!, '-');\n }\n fullySanitizedValue = fullySanitizedValue.replace(this.symbols.numeral, this.symbols.index);\n\n if (this.options.style === 'percent') {\n // javascript is bad at dividing by 100 and maintaining the same significant figures, so perform it on the string before parsing\n let isNegative = fullySanitizedValue.indexOf('-');\n fullySanitizedValue = fullySanitizedValue.replace('-', '');\n fullySanitizedValue = fullySanitizedValue.replace('+', '');\n let index = fullySanitizedValue.indexOf('.');\n if (index === -1) {\n index = fullySanitizedValue.length;\n }\n fullySanitizedValue = fullySanitizedValue.replace('.', '');\n if (index - 2 === 0) {\n fullySanitizedValue = `0.${fullySanitizedValue}`;\n } else if (index - 2 === -1) {\n fullySanitizedValue = `0.0${fullySanitizedValue}`;\n } else if (index - 2 === -2) {\n fullySanitizedValue = '0.00';\n } else {\n fullySanitizedValue = `${fullySanitizedValue.slice(0, index - 2)}.${fullySanitizedValue.slice(index - 2)}`;\n }\n if (isNegative > -1) {\n fullySanitizedValue = `-${fullySanitizedValue}`;\n }\n }\n\n let newValue = fullySanitizedValue ? +fullySanitizedValue : NaN;\n if (isNaN(newValue)) {\n return NaN;\n }\n\n if (this.options.style === 'percent') {\n // extra step for rounding percents to what our formatter would output\n let options = {\n ...this.options,\n style: 'decimal' as const,\n minimumFractionDigits: Math.min((this.options.minimumFractionDigits ?? 0) + 2, 20),\n maximumFractionDigits: Math.min((this.options.maximumFractionDigits ?? 0) + 2, 20)\n };\n return (new NumberParser(this.locale, options)).parse(new NumberFormatter(this.locale, options).format(newValue));\n }\n\n // accounting will always be stripped to a positive number, so if it's accounting and has a () around everything, then we need to make it negative again\n if (this.options.currencySign === 'accounting' && CURRENCY_SIGN_REGEX.test(value)) {\n newValue = -1 * newValue;\n }\n return newValue;\n }\n\n sanitize(value: string) {\n let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;\n // If the value is only a unit and it matches one of the formatted numbers where the value is part of the unit and doesn't have any numerals, then\n // return the known value for that case.\n if (this.symbols.noNumeralUnits.length > 0 && this.symbols.noNumeralUnits.find(obj => obj.unit === value)) {\n return this.symbols.noNumeralUnits.find(obj => obj.unit === value)!.value.toString();\n }\n\n value = value.replace(this.symbols.literals, '');\n\n // Replace the ASCII minus sign with the minus sign used in the current locale\n // so that both are allowed in case the user's keyboard doesn't have the locale's minus sign.\n if (this.symbols.minusSign) {\n value = value.replace('-', this.symbols.minusSign);\n }\n\n // In arab numeral system, their decimal character is 1643, but most keyboards don't type that\n // instead they use the , (44) character or apparently the (1548) character.\n if (this.options.numberingSystem === 'arab') {\n if (this.symbols.decimal) {\n value = replaceAll(value, ',', this.symbols.decimal);\n value = replaceAll(value, String.fromCharCode(1548), this.symbols.decimal);\n }\n if (this.symbols.group && isGroupSymbolAllowed) {\n value = replaceAll(value, '.', this.symbols.group);\n }\n }\n\n // In some locale styles, such as swiss currency, the group character can be a special single quote\n // that keyboards don't typically have. This expands the character to include the easier to type single quote.\n if (this.symbols.group === '’' && value.includes(\"'\") && isGroupSymbolAllowed) {\n value = replaceAll(value, \"'\", this.symbols.group);\n }\n\n // fr-FR group character is narrow non-breaking space, char code 8239 (U+202F), but that's not a key on the french keyboard,\n // so allow space and non-breaking space as a group char as well\n if (this.options.locale === 'fr-FR' && this.symbols.group && isGroupSymbolAllowed) {\n value = replaceAll(value, ' ', this.symbols.group);\n value = replaceAll(value, /\\u00A0/g, this.symbols.group);\n }\n\n return value;\n }\n\n isValidPartialNumber(value: string, minValue: number = -Infinity, maxValue: number = Infinity): boolean {\n let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;\n value = this.sanitize(value);\n\n // Remove minus or plus sign, which must be at the start of the string.\n if (this.symbols.minusSign && value.startsWith(this.symbols.minusSign) && minValue < 0) {\n value = value.slice(this.symbols.minusSign.length);\n } else if (this.symbols.plusSign && value.startsWith(this.symbols.plusSign) && maxValue > 0) {\n value = value.slice(this.symbols.plusSign.length);\n }\n\n // Numbers that can't have any decimal values fail if a decimal character is typed\n if (this.symbols.decimal && value.indexOf(this.symbols.decimal) > -1 && this.options.maximumFractionDigits === 0) {\n return false;\n }\n\n // Remove numerals, groups, and decimals\n if (this.symbols.group && isGroupSymbolAllowed) {\n value = replaceAll(value, this.symbols.group, '');\n }\n value = value.replace(this.symbols.numeral, '');\n if (this.symbols.decimal) {\n value = value.replace(this.symbols.decimal, '');\n }\n\n // The number is valid if there are no remaining characters\n return value.length === 0;\n }\n}\n\nconst nonLiteralParts = new Set(['decimal', 'fraction', 'integer', 'minusSign', 'plusSign', 'group']);\n\n// This list is derived from https://www.unicode.org/cldr/charts/43/supplemental/language_plural_rules.html#comparison and includes\n// all unique numbers which we need to check in order to determine all the plural forms for a given locale.\n// See: https://github.com/adobe/react-spectrum/pull/5134/files#r1337037855 for used script\nconst pluralNumbers = [\n 0, 4, 2, 1, 11, 20, 3, 7, 100, 21, 0.1, 1.1\n];\n\nfunction getSymbols(locale: string, formatter: Intl.NumberFormat, intlOptions: Intl.ResolvedNumberFormatOptions, originalOptions: Intl.NumberFormatOptions): Symbols {\n // formatter needs access to all decimal places in order to generate the correct literal strings for the plural set\n let symbolFormatter = new Intl.NumberFormat(locale, {...intlOptions,\n // Resets so we get the full range of symbols\n minimumSignificantDigits: 1,\n maximumSignificantDigits: 21,\n roundingIncrement: 1,\n roundingPriority: 'auto',\n roundingMode: 'halfExpand',\n useGrouping: true\n });\n // Note: some locale's don't add a group symbol until there is a ten thousands place\n let allParts = symbolFormatter.formatToParts(-10000.111);\n let posAllParts = symbolFormatter.formatToParts(10000.111);\n let pluralParts = pluralNumbers.map(n => symbolFormatter.formatToParts(n));\n // if the plural parts include a unit but no integer or fraction, then we need to add the unit to the special set\n let noNumeralUnits = pluralParts.map((p, i) => {\n let unit = p.find(p => p.type === 'unit');\n if (unit && !p.some(p => p.type === 'integer' || p.type === 'fraction')) {\n return {unit: unit.value, value: pluralNumbers[i]};\n }\n return null;\n }).filter(p => !!p);\n\n let minusSign = allParts.find(p => p.type === 'minusSign')?.value ?? '-';\n let plusSign = posAllParts.find(p => p.type === 'plusSign')?.value;\n\n // Safari does not support the signDisplay option, but our number parser polyfills it.\n // If no plus sign was returned, but the original options contained signDisplay, default to the '+' character.\n if (!plusSign && (originalOptions?.signDisplay === 'exceptZero' || originalOptions?.signDisplay === 'always')) {\n plusSign = '+';\n }\n\n // If maximumSignificantDigits is 1 (the minimum) then we won't get decimal characters out of the above formatters\n // Percent also defaults to 0 fractionDigits, so we need to make a new one that isn't percent to get an accurate decimal\n let decimalParts = new Intl.NumberFormat(locale, {...intlOptions, minimumFractionDigits: 2, maximumFractionDigits: 2}).formatToParts(0.001);\n\n let decimal = decimalParts.find(p => p.type === 'decimal')?.value;\n let group = allParts.find(p => p.type === 'group')?.value;\n\n // this set is also for a regex, it's all literals that might be in the string we want to eventually parse that\n // don't contribute to the numerical value\n let allPartsLiterals = allParts.filter(p => !nonLiteralParts.has(p.type)).map(p => escapeRegex(p.value));\n let pluralPartsLiterals = pluralParts.flatMap(p => p.filter(p => !nonLiteralParts.has(p.type)).map(p => escapeRegex(p.value)));\n let sortedLiterals = [...new Set([...allPartsLiterals, ...pluralPartsLiterals])].sort((a, b) => b.length - a.length);\n\n // Match both whitespace and formatting characters\n let literals = sortedLiterals.length === 0 ?\n new RegExp('\\\\p{White_Space}|\\\\p{Cf}', 'gu') :\n new RegExp(`${sortedLiterals.join('|')}|\\\\p{White_Space}|\\\\p{Cf}`, 'gu');\n\n // These are for replacing non-latn characters with the latn equivalent\n let numerals = [...new Intl.NumberFormat(intlOptions.locale, {useGrouping: false}).format(9876543210)].reverse();\n let indexes = new Map(numerals.map((d, i) => [d, i]));\n let numeral = new RegExp(`[${numerals.join('')}]`, 'g');\n let index = d => String(indexes.get(d));\n\n return {minusSign, plusSign, decimal, group, literals, numeral, numerals, index, noNumeralUnits};\n}\n\nfunction replaceAll(str: string, find: string | RegExp, replace: string) {\n if (str.replaceAll) {\n return str.replaceAll(find, replace);\n }\n\n return str.split(find).join(replace);\n}\n\nfunction escapeRegex(string: string) {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n"],"names":[],"version":3,"file":"NumberParser.mjs.map"}
1
+ {"mappings":"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","sources":["packages/@internationalized/number/src/NumberParser.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {NumberFormatter} from './NumberFormatter';\n\ninterface Symbols {\n minusSign?: string;\n plusSign?: string;\n decimal?: string;\n group?: string;\n literals: RegExp;\n numeral: RegExp;\n numerals: string[];\n index: (v: string) => string;\n noNumeralUnits: Array<{unit: string; value: number}>;\n}\n\nconst CURRENCY_SIGN_REGEX = new RegExp('^.*\\\\(.*\\\\).*$');\nconst NUMBERING_SYSTEMS = ['latn', 'arab', 'hanidec', 'deva', 'beng', 'fullwide'];\n\n/**\n * A NumberParser can be used to perform locale-aware parsing of numbers from Unicode strings,\n * as well as validation of partial user input. It automatically detects the numbering system\n * used in the input, and supports parsing decimals, percentages, currency values, and units\n * according to the locale.\n */\nexport class NumberParser {\n private locale: string;\n private options: Intl.NumberFormatOptions;\n\n constructor(locale: string, options: Intl.NumberFormatOptions = {}) {\n this.locale = locale;\n this.options = options;\n }\n\n /**\n * Parses the given string to a number. Returns NaN if a valid number could not be parsed.\n */\n parse(value: string): number {\n return getNumberParserImpl(this.locale, this.options, value).parse(value);\n }\n\n /**\n * Returns whether the given string could potentially be a valid number. This should be used to\n * validate user input as the user types. If a `minValue` or `maxValue` is provided, the validity\n * of the minus/plus sign characters can be checked.\n */\n isValidPartialNumber(value: string, minValue?: number, maxValue?: number): boolean {\n return getNumberParserImpl(this.locale, this.options, value).isValidPartialNumber(\n value,\n minValue,\n maxValue\n );\n }\n\n /**\n * Returns a numbering system for which the given string is valid in the current locale.\n * If no numbering system could be detected, the default numbering system for the current\n * locale is returned.\n */\n getNumberingSystem(value: string): string {\n return getNumberParserImpl(this.locale, this.options, value).options.numberingSystem;\n }\n}\n\nconst numberParserCache = new Map<string, NumberParserImpl>();\nfunction getNumberParserImpl(locale: string, options: Intl.NumberFormatOptions, value: string) {\n // First try the default numbering system for the provided locale\n let defaultParser = getCachedNumberParser(locale, options);\n\n // If that doesn't match, and the locale doesn't include a hard coded numbering system,\n // try each of the other supported numbering systems until we find one that matches.\n if (!locale.includes('-nu-') && !defaultParser.isValidPartialNumber(value)) {\n for (let numberingSystem of NUMBERING_SYSTEMS) {\n if (numberingSystem !== defaultParser.options.numberingSystem) {\n let parser = getCachedNumberParser(\n locale + (locale.includes('-u-') ? '-nu-' : '-u-nu-') + numberingSystem,\n options\n );\n if (parser.isValidPartialNumber(value)) {\n return parser;\n }\n }\n }\n }\n\n return defaultParser;\n}\n\nfunction getCachedNumberParser(locale: string, options: Intl.NumberFormatOptions) {\n let cacheKey =\n locale +\n (options\n ? Object.entries(options)\n .sort((a, b) => (a[0] < b[0] ? -1 : 1))\n .join()\n : '');\n let parser = numberParserCache.get(cacheKey);\n if (!parser) {\n parser = new NumberParserImpl(locale, options);\n numberParserCache.set(cacheKey, parser);\n }\n\n return parser;\n}\n\n// The actual number parser implementation. Instances of this class are cached\n// based on the locale, options, and detected numbering system.\nclass NumberParserImpl {\n formatter: Intl.NumberFormat;\n options: Intl.ResolvedNumberFormatOptions;\n symbols: Symbols;\n locale: string;\n\n constructor(locale: string, options: Intl.NumberFormatOptions = {}) {\n this.locale = locale;\n // see https://tc39.es/ecma402/#sec-setnfdigitoptions, when using roundingIncrement, the maximumFractionDigits and minimumFractionDigits must be equal\n // by default, they are 0 and 3 respectively, so we set them to 0 if neither are set\n if (options.roundingIncrement !== 1 && options.roundingIncrement != null) {\n if (options.maximumFractionDigits == null && options.minimumFractionDigits == null) {\n options.maximumFractionDigits = 0;\n options.minimumFractionDigits = 0;\n } else if (options.maximumFractionDigits == null) {\n options.maximumFractionDigits = options.minimumFractionDigits;\n } else if (options.minimumFractionDigits == null) {\n options.minimumFractionDigits = options.maximumFractionDigits;\n }\n // if both are specified, let the normal Range Error be thrown\n }\n this.formatter = new Intl.NumberFormat(locale, options);\n this.options = this.formatter.resolvedOptions();\n this.symbols = getSymbols(locale, this.formatter, this.options, options);\n if (\n this.options.style === 'percent' &&\n ((this.options.minimumFractionDigits ?? 0) > 18 ||\n (this.options.maximumFractionDigits ?? 0) > 18)\n ) {\n console.warn(\n 'NumberParser cannot handle percentages with greater than 18 decimal places, please reduce the number in your options.'\n );\n }\n }\n\n parse(value: string) {\n let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;\n // to parse the number, we need to remove anything that isn't actually part of the number, for example we want '-10.40' not '-10.40 USD'\n let fullySanitizedValue = this.sanitize(value);\n\n // Return NaN if there is a group symbol but useGrouping is false\n if (\n !isGroupSymbolAllowed &&\n this.symbols.group &&\n fullySanitizedValue.includes(this.symbols.group)\n ) {\n return NaN;\n } else if (this.symbols.group) {\n fullySanitizedValue = fullySanitizedValue.replaceAll(this.symbols.group!, '');\n }\n\n if (this.symbols.decimal) {\n fullySanitizedValue = fullySanitizedValue.replace(this.symbols.decimal!, '.');\n }\n if (this.symbols.minusSign) {\n fullySanitizedValue = fullySanitizedValue.replace(this.symbols.minusSign!, '-');\n }\n fullySanitizedValue = fullySanitizedValue.replace(this.symbols.numeral, this.symbols.index);\n\n if (this.options.style === 'percent') {\n // javascript is bad at dividing by 100 and maintaining the same significant figures, so perform it on the string before parsing\n let isNegative = fullySanitizedValue.indexOf('-');\n fullySanitizedValue = fullySanitizedValue.replace('-', '');\n fullySanitizedValue = fullySanitizedValue.replace('+', '');\n let index = fullySanitizedValue.indexOf('.');\n if (index === -1) {\n index = fullySanitizedValue.length;\n }\n fullySanitizedValue = fullySanitizedValue.replace('.', '');\n if (index - 2 === 0) {\n fullySanitizedValue = `0.${fullySanitizedValue}`;\n } else if (index - 2 === -1) {\n fullySanitizedValue = `0.0${fullySanitizedValue}`;\n } else if (index - 2 === -2) {\n fullySanitizedValue = '0.00';\n } else {\n fullySanitizedValue = `${fullySanitizedValue.slice(0, index - 2)}.${fullySanitizedValue.slice(index - 2)}`;\n }\n if (isNegative > -1) {\n fullySanitizedValue = `-${fullySanitizedValue}`;\n }\n }\n\n let newValue = fullySanitizedValue ? +fullySanitizedValue : NaN;\n if (isNaN(newValue)) {\n return NaN;\n }\n\n if (this.options.style === 'percent') {\n // extra step for rounding percents to what our formatter would output\n let options = {\n ...this.options,\n style: 'decimal' as const,\n minimumFractionDigits: Math.min((this.options.minimumFractionDigits ?? 0) + 2, 20),\n maximumFractionDigits: Math.min((this.options.maximumFractionDigits ?? 0) + 2, 20)\n };\n return new NumberParser(this.locale, options).parse(\n new NumberFormatter(this.locale, options).format(newValue)\n );\n }\n\n // accounting will always be stripped to a positive number, so if it's accounting and has a () around everything, then we need to make it negative again\n if (this.options.currencySign === 'accounting' && CURRENCY_SIGN_REGEX.test(value)) {\n newValue = -1 * newValue;\n }\n return newValue;\n }\n\n sanitize(value: string) {\n let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;\n // If the value is only a unit and it matches one of the formatted numbers where the value is part of the unit and doesn't have any numerals, then\n // return the known value for that case.\n if (\n this.symbols.noNumeralUnits.length > 0 &&\n this.symbols.noNumeralUnits.find(obj => obj.unit === value)\n ) {\n return this.symbols.noNumeralUnits.find(obj => obj.unit === value)!.value.toString();\n }\n\n value = value.replace(this.symbols.literals, '');\n\n // Replace the ASCII minus sign with the minus sign used in the current locale\n // so that both are allowed in case the user's keyboard doesn't have the locale's minus sign.\n if (this.symbols.minusSign) {\n value = value.replace('-', this.symbols.minusSign);\n }\n\n // In arab numeral system, their decimal character is 1643, but most keyboards don't type that\n // instead they use the , (44) character or apparently the (1548) character.\n if (this.options.numberingSystem === 'arab') {\n if (this.symbols.decimal) {\n value = replaceAll(value, ',', this.symbols.decimal);\n value = replaceAll(value, String.fromCharCode(1548), this.symbols.decimal);\n }\n if (this.symbols.group && isGroupSymbolAllowed) {\n value = replaceAll(value, '.', this.symbols.group);\n }\n }\n\n // In some locale styles, such as swiss currency, the group character can be a special single quote\n // that keyboards don't typically have. This expands the character to include the easier to type single quote.\n if (this.symbols.group === '’' && value.includes(\"'\") && isGroupSymbolAllowed) {\n value = replaceAll(value, \"'\", this.symbols.group);\n }\n\n // On newer ICU versions, the special single quote has been normalized, so we need to backport.\n if (this.symbols.group === \"'\" && value.includes('’') && isGroupSymbolAllowed) {\n value = replaceAll(value, '’', this.symbols.group);\n }\n\n // fr-FR group character is narrow non-breaking space, char code 8239 (U+202F), but that's not a key on the french keyboard,\n // so allow space and non-breaking space as a group char as well\n if (this.options.locale === 'fr-FR' && this.symbols.group && isGroupSymbolAllowed) {\n value = replaceAll(value, ' ', this.symbols.group);\n value = replaceAll(value, /\\u00A0/g, this.symbols.group);\n }\n\n return value;\n }\n\n isValidPartialNumber(\n value: string,\n minValue: number = -Infinity,\n maxValue: number = Infinity\n ): boolean {\n let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;\n value = this.sanitize(value);\n\n // Remove minus or plus sign, which must be at the start of the string.\n if (this.symbols.minusSign && value.startsWith(this.symbols.minusSign) && minValue < 0) {\n value = value.slice(this.symbols.minusSign.length);\n } else if (this.symbols.plusSign && value.startsWith(this.symbols.plusSign) && maxValue > 0) {\n value = value.slice(this.symbols.plusSign.length);\n }\n\n // Numbers that can't have any decimal values fail if a decimal character is typed\n if (\n this.symbols.decimal &&\n value.indexOf(this.symbols.decimal) > -1 &&\n this.options.maximumFractionDigits === 0\n ) {\n return false;\n }\n\n // Remove numerals, groups, and decimals\n if (this.symbols.group && isGroupSymbolAllowed) {\n value = replaceAll(value, this.symbols.group, '');\n }\n value = value.replace(this.symbols.numeral, '');\n if (this.symbols.decimal) {\n value = value.replace(this.symbols.decimal, '');\n }\n\n // The number is valid if there are no remaining characters\n return value.length === 0;\n }\n}\n\nconst nonLiteralParts = new Set([\n 'decimal',\n 'fraction',\n 'integer',\n 'minusSign',\n 'plusSign',\n 'group'\n]);\n\n// This list is derived from https://www.unicode.org/cldr/charts/49/supplemental/language_plural_rules.html#comparison and includes\n// all unique numbers which we need to check in order to determine all the plural forms for a given locale.\n// Run scripts/generateAllPlurals.mjs to generate this list.\nconst pluralNumbers = [0, 4, 2, 1, 11, 20, 3, 7, 100, 21, 0.1, 1.1];\n\nfunction getSymbols(\n locale: string,\n formatter: Intl.NumberFormat,\n intlOptions: Intl.ResolvedNumberFormatOptions,\n originalOptions: Intl.NumberFormatOptions\n): Symbols {\n // formatter needs access to all decimal places in order to generate the correct literal strings for the plural set\n let symbolFormatter = new Intl.NumberFormat(locale, {\n ...intlOptions,\n // Resets so we get the full range of symbols\n minimumSignificantDigits: 1,\n maximumSignificantDigits: 21,\n roundingIncrement: 1,\n roundingPriority: 'auto',\n roundingMode: 'halfExpand',\n useGrouping: true\n });\n // Note: some locale's don't add a group symbol until there is a ten thousands place\n let allParts = symbolFormatter.formatToParts(-10000.111);\n let posAllParts = symbolFormatter.formatToParts(10000.111);\n let pluralParts = pluralNumbers.map(n => symbolFormatter.formatToParts(n));\n // if the plural parts include a unit but no integer or fraction, then we need to add the unit to the special set\n let noNumeralUnits = pluralParts\n .map((p, i) => {\n let unit = p.find(p => p.type === 'unit');\n if (unit && !p.some(p => p.type === 'integer' || p.type === 'fraction')) {\n return {unit: unit.value, value: pluralNumbers[i]};\n }\n return null;\n })\n .filter(p => !!p);\n\n let minusSign = allParts.find(p => p.type === 'minusSign')?.value ?? '-';\n let plusSign = posAllParts.find(p => p.type === 'plusSign')?.value;\n\n // Safari does not support the signDisplay option, but our number parser polyfills it.\n // If no plus sign was returned, but the original options contained signDisplay, default to the '+' character.\n if (\n !plusSign &&\n (originalOptions?.signDisplay === 'exceptZero' || originalOptions?.signDisplay === 'always')\n ) {\n plusSign = '+';\n }\n\n // If maximumSignificantDigits is 1 (the minimum) then we won't get decimal characters out of the above formatters\n // Percent also defaults to 0 fractionDigits, so we need to make a new one that isn't percent to get an accurate decimal\n let decimalParts = new Intl.NumberFormat(locale, {\n ...intlOptions,\n minimumFractionDigits: 2,\n maximumFractionDigits: 2\n }).formatToParts(0.001);\n\n let decimal = decimalParts.find(p => p.type === 'decimal')?.value;\n let group = allParts.find(p => p.type === 'group')?.value;\n\n // this set is also for a regex, it's all literals that might be in the string we want to eventually parse that\n // don't contribute to the numerical value\n let allPartsLiterals = allParts\n .filter(p => !nonLiteralParts.has(p.type))\n .map(p => escapeRegex(p.value));\n let pluralPartsLiterals = pluralParts.flatMap(p =>\n p.filter(p => !nonLiteralParts.has(p.type)).map(p => escapeRegex(p.value))\n );\n let sortedLiterals = [...new Set([...allPartsLiterals, ...pluralPartsLiterals])].sort(\n (a, b) => b.length - a.length\n );\n\n // Match both whitespace and formatting characters\n let literals =\n sortedLiterals.length === 0\n ? new RegExp('\\\\p{White_Space}|\\\\p{Cf}', 'gu')\n : new RegExp(`${sortedLiterals.join('|')}|\\\\p{White_Space}|\\\\p{Cf}`, 'gu');\n\n // These are for replacing non-latn characters with the latn equivalent\n let numerals = [\n ...new Intl.NumberFormat(intlOptions.locale, {useGrouping: false}).format(9876543210)\n ].reverse();\n let indexes = new Map(numerals.map((d, i) => [d, i]));\n let numeral = new RegExp(`[${numerals.join('')}]`, 'g');\n let index = d => String(indexes.get(d));\n\n return {minusSign, plusSign, decimal, group, literals, numeral, numerals, index, noNumeralUnits};\n}\n\nfunction replaceAll(str: string, find: string | RegExp, replace: string) {\n if (str.replaceAll) {\n return str.replaceAll(find, replace);\n }\n\n return str.split(find).join(replace);\n}\n\nfunction escapeRegex(string: string) {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n"],"names":[],"version":3,"file":"NumberParser.mjs.map"}
@@ -6,13 +6,17 @@ interface NumberRangeFormatPart extends Intl.NumberFormatPart {
6
6
  source: 'startRange' | 'endRange' | 'shared';
7
7
  }
8
8
  /**
9
- * A wrapper around Intl.NumberFormat providing additional options, polyfills, and caching for performance.
9
+ * A wrapper around Intl.NumberFormat providing additional options, polyfills, and caching for
10
+ * performance.
10
11
  */
11
12
  export declare class NumberFormatter implements Intl.NumberFormat {
12
13
  private numberFormatter;
13
14
  private options;
14
15
  constructor(locale: string, options?: NumberFormatOptions);
15
- /** Formats a number value as a string, according to the locale and options provided to the constructor. */
16
+ /**
17
+ * Formats a number value as a string, according to the locale and options provided to the
18
+ * constructor.
19
+ */
16
20
  format(value: number): string;
17
21
  /** Formats a number to an array of parts such as separators, digits, punctuation, and more. */
18
22
  formatToParts(value: number): Intl.NumberFormatPart[];
@@ -23,6 +27,6 @@ export declare class NumberFormatter implements Intl.NumberFormat {
23
27
  /** Returns the resolved formatting options based on the values passed to the constructor. */
24
28
  resolvedOptions(): Intl.ResolvedNumberFormatOptions;
25
29
  }
26
- /** @private - exported for tests */
30
+ /** @private - Exported for tests */
27
31
  export declare function numberFormatSignDisplayPolyfill(numberFormat: Intl.NumberFormat, signDisplay: string, num: number): string;
28
32
  export {};
package/package.json CHANGED
@@ -1,34 +1,34 @@
1
1
  {
2
2
  "name": "@internationalized/number",
3
- "version": "3.6.6",
3
+ "version": "3.6.7",
4
4
  "description": "Internationalized number formatting and parsing utilities",
5
5
  "license": "Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/adobe/react-spectrum"
9
+ },
10
+ "source": "src/index.ts",
11
+ "files": [
12
+ "dist",
13
+ "src"
14
+ ],
15
+ "sideEffects": false,
6
16
  "main": "dist/index.cjs",
7
17
  "module": "dist/index.js",
8
- "import": "dist/index.mjs",
18
+ "types": "./dist/types/src/index.d.ts",
9
19
  "exports": {
10
20
  "source": "./src/index.ts",
11
21
  "types": "./dist/types/src/index.d.ts",
12
22
  "import": "./dist/index.mjs",
13
23
  "require": "./dist/index.cjs"
14
24
  },
15
- "types": "./dist/types/src/index.d.ts",
16
- "source": "src/index.ts",
17
- "files": [
18
- "dist",
19
- "src"
20
- ],
21
- "sideEffects": false,
22
- "repository": {
23
- "type": "git",
24
- "url": "https://github.com/adobe/react-spectrum"
25
+ "publishConfig": {
26
+ "access": "public"
25
27
  },
26
28
  "dependencies": {
27
29
  "@swc/helpers": "^0.5.0"
28
30
  },
29
- "publishConfig": {
30
- "access": "public"
31
- },
31
+ "import": "dist/index.mjs",
32
32
  "targets": {
33
33
  "types": false,
34
34
  "module": {
@@ -46,5 +46,5 @@
46
46
  "includeNodeModules": false
47
47
  }
48
48
  },
49
- "gitHead": "a6999bdf494a2e9c0381a5881908328bdd22ddae"
49
+ "gitHead": "3577a20859b9585a000010c720f6ee39c1c588cc"
50
50
  }
@@ -14,13 +14,17 @@ let formatterCache = new Map<string, Intl.NumberFormat>();
14
14
 
15
15
  let supportsSignDisplay = false;
16
16
  try {
17
- supportsSignDisplay = (new Intl.NumberFormat('de-DE', {signDisplay: 'exceptZero'})).resolvedOptions().signDisplay === 'exceptZero';
17
+ supportsSignDisplay =
18
+ new Intl.NumberFormat('de-DE', {signDisplay: 'exceptZero'}).resolvedOptions().signDisplay ===
19
+ 'exceptZero';
18
20
  // eslint-disable-next-line no-empty
19
21
  } catch {}
20
22
 
21
23
  let supportsUnit = false;
22
24
  try {
23
- supportsUnit = (new Intl.NumberFormat('de-DE', {style: 'unit', unit: 'degree'})).resolvedOptions().style === 'unit';
25
+ supportsUnit =
26
+ new Intl.NumberFormat('de-DE', {style: 'unit', unit: 'degree'}).resolvedOptions().style ===
27
+ 'unit';
24
28
  // eslint-disable-next-line no-empty
25
29
  } catch {}
26
30
 
@@ -42,15 +46,16 @@ const UNITS = {
42
46
 
43
47
  export interface NumberFormatOptions extends Intl.NumberFormatOptions {
44
48
  /** Overrides default numbering system for the current locale. */
45
- numberingSystem?: string
49
+ numberingSystem?: string;
46
50
  }
47
51
 
48
52
  interface NumberRangeFormatPart extends Intl.NumberFormatPart {
49
- source: 'startRange' | 'endRange' | 'shared'
53
+ source: 'startRange' | 'endRange' | 'shared';
50
54
  }
51
55
 
52
56
  /**
53
- * A wrapper around Intl.NumberFormat providing additional options, polyfills, and caching for performance.
57
+ * A wrapper around Intl.NumberFormat providing additional options, polyfills, and caching for
58
+ * performance.
54
59
  */
55
60
  export class NumberFormatter implements Intl.NumberFormat {
56
61
  private numberFormatter: Intl.NumberFormat;
@@ -61,7 +66,10 @@ export class NumberFormatter implements Intl.NumberFormat {
61
66
  this.options = options;
62
67
  }
63
68
 
64
- /** Formats a number value as a string, according to the locale and options provided to the constructor. */
69
+ /**
70
+ * Formats a number value as a string, according to the locale and options provided to the
71
+ * constructor.
72
+ */
65
73
  format(value: number): string {
66
74
  let res = '';
67
75
  if (!supportsSignDisplay && this.options.signDisplay != null) {
@@ -115,9 +123,9 @@ export class NumberFormatter implements Intl.NumberFormat {
115
123
  let startParts = this.numberFormatter.formatToParts(start);
116
124
  let endParts = this.numberFormatter.formatToParts(end);
117
125
  return [
118
- ...startParts.map(p => ({...p, source: 'startRange'} as NumberRangeFormatPart)),
126
+ ...startParts.map(p => ({...p, source: 'startRange'}) as NumberRangeFormatPart),
119
127
  {type: 'literal', value: ' – ', source: 'shared'},
120
- ...endParts.map(p => ({...p, source: 'endRange'} as NumberRangeFormatPart))
128
+ ...endParts.map(p => ({...p, source: 'endRange'}) as NumberRangeFormatPart)
121
129
  ];
122
130
  }
123
131
 
@@ -129,14 +137,22 @@ export class NumberFormatter implements Intl.NumberFormat {
129
137
  }
130
138
 
131
139
  if (!supportsUnit && this.options.style === 'unit') {
132
- options = {...options, style: 'unit', unit: this.options.unit, unitDisplay: this.options.unitDisplay};
140
+ options = {
141
+ ...options,
142
+ style: 'unit',
143
+ unit: this.options.unit,
144
+ unitDisplay: this.options.unitDisplay
145
+ };
133
146
  }
134
147
 
135
148
  return options;
136
149
  }
137
150
  }
138
151
 
139
- function getCachedNumberFormatter(locale: string, options: NumberFormatOptions = {}): Intl.NumberFormat {
152
+ function getCachedNumberFormatter(
153
+ locale: string,
154
+ options: NumberFormatOptions = {}
155
+ ): Intl.NumberFormat {
140
156
  let {numberingSystem} = options;
141
157
  if (numberingSystem && locale.includes('-nu-')) {
142
158
  if (!locale.includes('-u-')) {
@@ -156,7 +172,13 @@ function getCachedNumberFormatter(locale: string, options: NumberFormatOptions =
156
172
  options = {...options, style: 'decimal'};
157
173
  }
158
174
 
159
- let cacheKey = locale + (options ? Object.entries(options).sort((a, b) => a[0] < b[0] ? -1 : 1).join() : '');
175
+ let cacheKey =
176
+ locale +
177
+ (options
178
+ ? Object.entries(options)
179
+ .sort((a, b) => (a[0] < b[0] ? -1 : 1))
180
+ .join()
181
+ : '');
160
182
  if (formatterCache.has(cacheKey)) {
161
183
  return formatterCache.get(cacheKey)!;
162
184
  }
@@ -166,8 +188,12 @@ function getCachedNumberFormatter(locale: string, options: NumberFormatOptions =
166
188
  return numberFormatter;
167
189
  }
168
190
 
169
- /** @private - exported for tests */
170
- export function numberFormatSignDisplayPolyfill(numberFormat: Intl.NumberFormat, signDisplay: string, num: number): string {
191
+ /** @private - Exported for tests */
192
+ export function numberFormatSignDisplayPolyfill(
193
+ numberFormat: Intl.NumberFormat,
194
+ signDisplay: string,
195
+ num: number
196
+ ): string {
171
197
  if (signDisplay === 'auto') {
172
198
  return numberFormat.format(num);
173
199
  } else if (signDisplay === 'never') {
@@ -13,15 +13,15 @@
13
13
  import {NumberFormatter} from './NumberFormatter';
14
14
 
15
15
  interface Symbols {
16
- minusSign?: string,
17
- plusSign?: string,
18
- decimal?: string,
19
- group?: string,
20
- literals: RegExp,
21
- numeral: RegExp,
22
- numerals: string[],
23
- index: (v: string) => string,
24
- noNumeralUnits: Array<{unit: string, value: number}>
16
+ minusSign?: string;
17
+ plusSign?: string;
18
+ decimal?: string;
19
+ group?: string;
20
+ literals: RegExp;
21
+ numeral: RegExp;
22
+ numerals: string[];
23
+ index: (v: string) => string;
24
+ noNumeralUnits: Array<{unit: string; value: number}>;
25
25
  }
26
26
 
27
27
  const CURRENCY_SIGN_REGEX = new RegExp('^.*\\(.*\\).*$');
@@ -55,7 +55,11 @@ export class NumberParser {
55
55
  * of the minus/plus sign characters can be checked.
56
56
  */
57
57
  isValidPartialNumber(value: string, minValue?: number, maxValue?: number): boolean {
58
- return getNumberParserImpl(this.locale, this.options, value).isValidPartialNumber(value, minValue, maxValue);
58
+ return getNumberParserImpl(this.locale, this.options, value).isValidPartialNumber(
59
+ value,
60
+ minValue,
61
+ maxValue
62
+ );
59
63
  }
60
64
 
61
65
  /**
@@ -78,7 +82,10 @@ function getNumberParserImpl(locale: string, options: Intl.NumberFormatOptions,
78
82
  if (!locale.includes('-nu-') && !defaultParser.isValidPartialNumber(value)) {
79
83
  for (let numberingSystem of NUMBERING_SYSTEMS) {
80
84
  if (numberingSystem !== defaultParser.options.numberingSystem) {
81
- let parser = getCachedNumberParser(locale + (locale.includes('-u-') ? '-nu-' : '-u-nu-') + numberingSystem, options);
85
+ let parser = getCachedNumberParser(
86
+ locale + (locale.includes('-u-') ? '-nu-' : '-u-nu-') + numberingSystem,
87
+ options
88
+ );
82
89
  if (parser.isValidPartialNumber(value)) {
83
90
  return parser;
84
91
  }
@@ -90,7 +97,13 @@ function getNumberParserImpl(locale: string, options: Intl.NumberFormatOptions,
90
97
  }
91
98
 
92
99
  function getCachedNumberParser(locale: string, options: Intl.NumberFormatOptions) {
93
- let cacheKey = locale + (options ? Object.entries(options).sort((a, b) => a[0] < b[0] ? -1 : 1).join() : '');
100
+ let cacheKey =
101
+ locale +
102
+ (options
103
+ ? Object.entries(options)
104
+ .sort((a, b) => (a[0] < b[0] ? -1 : 1))
105
+ .join()
106
+ : '');
94
107
  let parser = numberParserCache.get(cacheKey);
95
108
  if (!parser) {
96
109
  parser = new NumberParserImpl(locale, options);
@@ -126,8 +139,14 @@ class NumberParserImpl {
126
139
  this.formatter = new Intl.NumberFormat(locale, options);
127
140
  this.options = this.formatter.resolvedOptions();
128
141
  this.symbols = getSymbols(locale, this.formatter, this.options, options);
129
- if (this.options.style === 'percent' && ((this.options.minimumFractionDigits ?? 0) > 18 || (this.options.maximumFractionDigits ?? 0) > 18)) {
130
- console.warn('NumberParser cannot handle percentages with greater than 18 decimal places, please reduce the number in your options.');
142
+ if (
143
+ this.options.style === 'percent' &&
144
+ ((this.options.minimumFractionDigits ?? 0) > 18 ||
145
+ (this.options.maximumFractionDigits ?? 0) > 18)
146
+ ) {
147
+ console.warn(
148
+ 'NumberParser cannot handle percentages with greater than 18 decimal places, please reduce the number in your options.'
149
+ );
131
150
  }
132
151
  }
133
152
 
@@ -137,7 +156,11 @@ class NumberParserImpl {
137
156
  let fullySanitizedValue = this.sanitize(value);
138
157
 
139
158
  // Return NaN if there is a group symbol but useGrouping is false
140
- if (!isGroupSymbolAllowed && this.symbols.group && fullySanitizedValue.includes(this.symbols.group)) {
159
+ if (
160
+ !isGroupSymbolAllowed &&
161
+ this.symbols.group &&
162
+ fullySanitizedValue.includes(this.symbols.group)
163
+ ) {
141
164
  return NaN;
142
165
  } else if (this.symbols.group) {
143
166
  fullySanitizedValue = fullySanitizedValue.replaceAll(this.symbols.group!, '');
@@ -188,7 +211,9 @@ class NumberParserImpl {
188
211
  minimumFractionDigits: Math.min((this.options.minimumFractionDigits ?? 0) + 2, 20),
189
212
  maximumFractionDigits: Math.min((this.options.maximumFractionDigits ?? 0) + 2, 20)
190
213
  };
191
- return (new NumberParser(this.locale, options)).parse(new NumberFormatter(this.locale, options).format(newValue));
214
+ return new NumberParser(this.locale, options).parse(
215
+ new NumberFormatter(this.locale, options).format(newValue)
216
+ );
192
217
  }
193
218
 
194
219
  // accounting will always be stripped to a positive number, so if it's accounting and has a () around everything, then we need to make it negative again
@@ -202,7 +227,10 @@ class NumberParserImpl {
202
227
  let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;
203
228
  // If the value is only a unit and it matches one of the formatted numbers where the value is part of the unit and doesn't have any numerals, then
204
229
  // return the known value for that case.
205
- if (this.symbols.noNumeralUnits.length > 0 && this.symbols.noNumeralUnits.find(obj => obj.unit === value)) {
230
+ if (
231
+ this.symbols.noNumeralUnits.length > 0 &&
232
+ this.symbols.noNumeralUnits.find(obj => obj.unit === value)
233
+ ) {
206
234
  return this.symbols.noNumeralUnits.find(obj => obj.unit === value)!.value.toString();
207
235
  }
208
236
 
@@ -232,6 +260,11 @@ class NumberParserImpl {
232
260
  value = replaceAll(value, "'", this.symbols.group);
233
261
  }
234
262
 
263
+ // On newer ICU versions, the special single quote has been normalized, so we need to backport.
264
+ if (this.symbols.group === "'" && value.includes('’') && isGroupSymbolAllowed) {
265
+ value = replaceAll(value, '’', this.symbols.group);
266
+ }
267
+
235
268
  // fr-FR group character is narrow non-breaking space, char code 8239 (U+202F), but that's not a key on the french keyboard,
236
269
  // so allow space and non-breaking space as a group char as well
237
270
  if (this.options.locale === 'fr-FR' && this.symbols.group && isGroupSymbolAllowed) {
@@ -242,7 +275,11 @@ class NumberParserImpl {
242
275
  return value;
243
276
  }
244
277
 
245
- isValidPartialNumber(value: string, minValue: number = -Infinity, maxValue: number = Infinity): boolean {
278
+ isValidPartialNumber(
279
+ value: string,
280
+ minValue: number = -Infinity,
281
+ maxValue: number = Infinity
282
+ ): boolean {
246
283
  let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;
247
284
  value = this.sanitize(value);
248
285
 
@@ -254,7 +291,11 @@ class NumberParserImpl {
254
291
  }
255
292
 
256
293
  // Numbers that can't have any decimal values fail if a decimal character is typed
257
- if (this.symbols.decimal && value.indexOf(this.symbols.decimal) > -1 && this.options.maximumFractionDigits === 0) {
294
+ if (
295
+ this.symbols.decimal &&
296
+ value.indexOf(this.symbols.decimal) > -1 &&
297
+ this.options.maximumFractionDigits === 0
298
+ ) {
258
299
  return false;
259
300
  }
260
301
 
@@ -272,18 +313,29 @@ class NumberParserImpl {
272
313
  }
273
314
  }
274
315
 
275
- const nonLiteralParts = new Set(['decimal', 'fraction', 'integer', 'minusSign', 'plusSign', 'group']);
316
+ const nonLiteralParts = new Set([
317
+ 'decimal',
318
+ 'fraction',
319
+ 'integer',
320
+ 'minusSign',
321
+ 'plusSign',
322
+ 'group'
323
+ ]);
276
324
 
277
- // This list is derived from https://www.unicode.org/cldr/charts/43/supplemental/language_plural_rules.html#comparison and includes
325
+ // This list is derived from https://www.unicode.org/cldr/charts/49/supplemental/language_plural_rules.html#comparison and includes
278
326
  // all unique numbers which we need to check in order to determine all the plural forms for a given locale.
279
- // See: https://github.com/adobe/react-spectrum/pull/5134/files#r1337037855 for used script
280
- const pluralNumbers = [
281
- 0, 4, 2, 1, 11, 20, 3, 7, 100, 21, 0.1, 1.1
282
- ];
283
-
284
- function getSymbols(locale: string, formatter: Intl.NumberFormat, intlOptions: Intl.ResolvedNumberFormatOptions, originalOptions: Intl.NumberFormatOptions): Symbols {
327
+ // Run scripts/generateAllPlurals.mjs to generate this list.
328
+ const pluralNumbers = [0, 4, 2, 1, 11, 20, 3, 7, 100, 21, 0.1, 1.1];
329
+
330
+ function getSymbols(
331
+ locale: string,
332
+ formatter: Intl.NumberFormat,
333
+ intlOptions: Intl.ResolvedNumberFormatOptions,
334
+ originalOptions: Intl.NumberFormatOptions
335
+ ): Symbols {
285
336
  // formatter needs access to all decimal places in order to generate the correct literal strings for the plural set
286
- let symbolFormatter = new Intl.NumberFormat(locale, {...intlOptions,
337
+ let symbolFormatter = new Intl.NumberFormat(locale, {
338
+ ...intlOptions,
287
339
  // Resets so we get the full range of symbols
288
340
  minimumSignificantDigits: 1,
289
341
  maximumSignificantDigits: 21,
@@ -297,43 +349,61 @@ function getSymbols(locale: string, formatter: Intl.NumberFormat, intlOptions: I
297
349
  let posAllParts = symbolFormatter.formatToParts(10000.111);
298
350
  let pluralParts = pluralNumbers.map(n => symbolFormatter.formatToParts(n));
299
351
  // if the plural parts include a unit but no integer or fraction, then we need to add the unit to the special set
300
- let noNumeralUnits = pluralParts.map((p, i) => {
301
- let unit = p.find(p => p.type === 'unit');
302
- if (unit && !p.some(p => p.type === 'integer' || p.type === 'fraction')) {
303
- return {unit: unit.value, value: pluralNumbers[i]};
304
- }
305
- return null;
306
- }).filter(p => !!p);
352
+ let noNumeralUnits = pluralParts
353
+ .map((p, i) => {
354
+ let unit = p.find(p => p.type === 'unit');
355
+ if (unit && !p.some(p => p.type === 'integer' || p.type === 'fraction')) {
356
+ return {unit: unit.value, value: pluralNumbers[i]};
357
+ }
358
+ return null;
359
+ })
360
+ .filter(p => !!p);
307
361
 
308
362
  let minusSign = allParts.find(p => p.type === 'minusSign')?.value ?? '-';
309
363
  let plusSign = posAllParts.find(p => p.type === 'plusSign')?.value;
310
364
 
311
365
  // Safari does not support the signDisplay option, but our number parser polyfills it.
312
366
  // If no plus sign was returned, but the original options contained signDisplay, default to the '+' character.
313
- if (!plusSign && (originalOptions?.signDisplay === 'exceptZero' || originalOptions?.signDisplay === 'always')) {
367
+ if (
368
+ !plusSign &&
369
+ (originalOptions?.signDisplay === 'exceptZero' || originalOptions?.signDisplay === 'always')
370
+ ) {
314
371
  plusSign = '+';
315
372
  }
316
373
 
317
374
  // If maximumSignificantDigits is 1 (the minimum) then we won't get decimal characters out of the above formatters
318
375
  // Percent also defaults to 0 fractionDigits, so we need to make a new one that isn't percent to get an accurate decimal
319
- let decimalParts = new Intl.NumberFormat(locale, {...intlOptions, minimumFractionDigits: 2, maximumFractionDigits: 2}).formatToParts(0.001);
376
+ let decimalParts = new Intl.NumberFormat(locale, {
377
+ ...intlOptions,
378
+ minimumFractionDigits: 2,
379
+ maximumFractionDigits: 2
380
+ }).formatToParts(0.001);
320
381
 
321
382
  let decimal = decimalParts.find(p => p.type === 'decimal')?.value;
322
383
  let group = allParts.find(p => p.type === 'group')?.value;
323
384
 
324
385
  // this set is also for a regex, it's all literals that might be in the string we want to eventually parse that
325
386
  // don't contribute to the numerical value
326
- let allPartsLiterals = allParts.filter(p => !nonLiteralParts.has(p.type)).map(p => escapeRegex(p.value));
327
- let pluralPartsLiterals = pluralParts.flatMap(p => p.filter(p => !nonLiteralParts.has(p.type)).map(p => escapeRegex(p.value)));
328
- let sortedLiterals = [...new Set([...allPartsLiterals, ...pluralPartsLiterals])].sort((a, b) => b.length - a.length);
387
+ let allPartsLiterals = allParts
388
+ .filter(p => !nonLiteralParts.has(p.type))
389
+ .map(p => escapeRegex(p.value));
390
+ let pluralPartsLiterals = pluralParts.flatMap(p =>
391
+ p.filter(p => !nonLiteralParts.has(p.type)).map(p => escapeRegex(p.value))
392
+ );
393
+ let sortedLiterals = [...new Set([...allPartsLiterals, ...pluralPartsLiterals])].sort(
394
+ (a, b) => b.length - a.length
395
+ );
329
396
 
330
397
  // Match both whitespace and formatting characters
331
- let literals = sortedLiterals.length === 0 ?
332
- new RegExp('\\p{White_Space}|\\p{Cf}', 'gu') :
333
- new RegExp(`${sortedLiterals.join('|')}|\\p{White_Space}|\\p{Cf}`, 'gu');
398
+ let literals =
399
+ sortedLiterals.length === 0
400
+ ? new RegExp('\\p{White_Space}|\\p{Cf}', 'gu')
401
+ : new RegExp(`${sortedLiterals.join('|')}|\\p{White_Space}|\\p{Cf}`, 'gu');
334
402
 
335
403
  // These are for replacing non-latn characters with the latn equivalent
336
- let numerals = [...new Intl.NumberFormat(intlOptions.locale, {useGrouping: false}).format(9876543210)].reverse();
404
+ let numerals = [
405
+ ...new Intl.NumberFormat(intlOptions.locale, {useGrouping: false}).format(9876543210)
406
+ ].reverse();
337
407
  let indexes = new Map(numerals.map((d, i) => [d, i]));
338
408
  let numeral = new RegExp(`[${numerals.join('')}]`, 'g');
339
409
  let index = d => String(indexes.get(d));