@internationalized/number 3.6.5 → 3.6.6

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.
@@ -1,4 +1,4 @@
1
- import {NumberFormatter as $488c6ddbf4ef74c2$export$cc77c4ff7e8673c5} from "./NumberFormatter.mjs";
1
+ import {NumberFormatter as $1dfb119a85e764e5$export$cc77c4ff7e8673c5} from "./NumberFormatter.mjs";
2
2
 
3
3
  /*
4
4
  * Copyright 2020 Adobe. All rights reserved.
@@ -11,8 +11,8 @@ import {NumberFormatter as $488c6ddbf4ef74c2$export$cc77c4ff7e8673c5} from "./Nu
11
11
  * OF ANY KIND, either express or implied. See the License for the specific language
12
12
  * governing permissions and limitations under the License.
13
13
  */
14
- const $6c7bd7858deea686$var$CURRENCY_SIGN_REGEX = new RegExp('^.*\\(.*\\).*$');
15
- const $6c7bd7858deea686$var$NUMBERING_SYSTEMS = [
14
+ const $eb76cf4feb040f77$var$CURRENCY_SIGN_REGEX = new RegExp('^.*\\(.*\\).*$');
15
+ const $eb76cf4feb040f77$var$NUMBERING_SYSTEMS = [
16
16
  'latn',
17
17
  'arab',
18
18
  'hanidec',
@@ -20,62 +20,81 @@ const $6c7bd7858deea686$var$NUMBERING_SYSTEMS = [
20
20
  'beng',
21
21
  'fullwide'
22
22
  ];
23
- class $6c7bd7858deea686$export$cd11ab140839f11d {
23
+ class $eb76cf4feb040f77$export$cd11ab140839f11d {
24
+ constructor(locale, options = {}){
25
+ this.locale = locale;
26
+ this.options = options;
27
+ }
24
28
  /**
25
29
  * Parses the given string to a number. Returns NaN if a valid number could not be parsed.
26
30
  */ parse(value) {
27
- return $6c7bd7858deea686$var$getNumberParserImpl(this.locale, this.options, value).parse(value);
31
+ return $eb76cf4feb040f77$var$getNumberParserImpl(this.locale, this.options, value).parse(value);
28
32
  }
29
33
  /**
30
34
  * Returns whether the given string could potentially be a valid number. This should be used to
31
35
  * validate user input as the user types. If a `minValue` or `maxValue` is provided, the validity
32
36
  * of the minus/plus sign characters can be checked.
33
37
  */ isValidPartialNumber(value, minValue, maxValue) {
34
- return $6c7bd7858deea686$var$getNumberParserImpl(this.locale, this.options, value).isValidPartialNumber(value, minValue, maxValue);
38
+ return $eb76cf4feb040f77$var$getNumberParserImpl(this.locale, this.options, value).isValidPartialNumber(value, minValue, maxValue);
35
39
  }
36
40
  /**
37
41
  * Returns a numbering system for which the given string is valid in the current locale.
38
42
  * If no numbering system could be detected, the default numbering system for the current
39
43
  * locale is returned.
40
44
  */ getNumberingSystem(value) {
41
- return $6c7bd7858deea686$var$getNumberParserImpl(this.locale, this.options, value).options.numberingSystem;
42
- }
43
- constructor(locale, options = {}){
44
- this.locale = locale;
45
- this.options = options;
45
+ return $eb76cf4feb040f77$var$getNumberParserImpl(this.locale, this.options, value).options.numberingSystem;
46
46
  }
47
47
  }
48
- const $6c7bd7858deea686$var$numberParserCache = new Map();
49
- function $6c7bd7858deea686$var$getNumberParserImpl(locale, options, value) {
48
+ const $eb76cf4feb040f77$var$numberParserCache = new Map();
49
+ function $eb76cf4feb040f77$var$getNumberParserImpl(locale, options, value) {
50
50
  // First try the default numbering system for the provided locale
51
- let defaultParser = $6c7bd7858deea686$var$getCachedNumberParser(locale, options);
51
+ let defaultParser = $eb76cf4feb040f77$var$getCachedNumberParser(locale, options);
52
52
  // If that doesn't match, and the locale doesn't include a hard coded numbering system,
53
53
  // try each of the other supported numbering systems until we find one that matches.
54
54
  if (!locale.includes('-nu-') && !defaultParser.isValidPartialNumber(value)) {
55
- for (let numberingSystem of $6c7bd7858deea686$var$NUMBERING_SYSTEMS)if (numberingSystem !== defaultParser.options.numberingSystem) {
56
- let parser = $6c7bd7858deea686$var$getCachedNumberParser(locale + (locale.includes('-u-') ? '-nu-' : '-u-nu-') + numberingSystem, options);
55
+ for (let numberingSystem of $eb76cf4feb040f77$var$NUMBERING_SYSTEMS)if (numberingSystem !== defaultParser.options.numberingSystem) {
56
+ let parser = $eb76cf4feb040f77$var$getCachedNumberParser(locale + (locale.includes('-u-') ? '-nu-' : '-u-nu-') + numberingSystem, options);
57
57
  if (parser.isValidPartialNumber(value)) return parser;
58
58
  }
59
59
  }
60
60
  return defaultParser;
61
61
  }
62
- function $6c7bd7858deea686$var$getCachedNumberParser(locale, options) {
62
+ function $eb76cf4feb040f77$var$getCachedNumberParser(locale, options) {
63
63
  let cacheKey = locale + (options ? Object.entries(options).sort((a, b)=>a[0] < b[0] ? -1 : 1).join() : '');
64
- let parser = $6c7bd7858deea686$var$numberParserCache.get(cacheKey);
64
+ let parser = $eb76cf4feb040f77$var$numberParserCache.get(cacheKey);
65
65
  if (!parser) {
66
- parser = new $6c7bd7858deea686$var$NumberParserImpl(locale, options);
67
- $6c7bd7858deea686$var$numberParserCache.set(cacheKey, parser);
66
+ parser = new $eb76cf4feb040f77$var$NumberParserImpl(locale, options);
67
+ $eb76cf4feb040f77$var$numberParserCache.set(cacheKey, parser);
68
68
  }
69
69
  return parser;
70
70
  }
71
71
  // The actual number parser implementation. Instances of this class are cached
72
72
  // based on the locale, options, and detected numbering system.
73
- class $6c7bd7858deea686$var$NumberParserImpl {
73
+ class $eb76cf4feb040f77$var$NumberParserImpl {
74
+ constructor(locale, options = {}){
75
+ this.locale = locale;
76
+ // see https://tc39.es/ecma402/#sec-setnfdigitoptions, when using roundingIncrement, the maximumFractionDigits and minimumFractionDigits must be equal
77
+ // by default, they are 0 and 3 respectively, so we set them to 0 if neither are set
78
+ if (options.roundingIncrement !== 1 && options.roundingIncrement != null) {
79
+ if (options.maximumFractionDigits == null && options.minimumFractionDigits == null) {
80
+ options.maximumFractionDigits = 0;
81
+ options.minimumFractionDigits = 0;
82
+ } else if (options.maximumFractionDigits == null) options.maximumFractionDigits = options.minimumFractionDigits;
83
+ else if (options.minimumFractionDigits == null) options.minimumFractionDigits = options.maximumFractionDigits;
84
+ // if both are specified, let the normal Range Error be thrown
85
+ }
86
+ this.formatter = new Intl.NumberFormat(locale, options);
87
+ this.options = this.formatter.resolvedOptions();
88
+ this.symbols = $eb76cf4feb040f77$var$getSymbols(locale, this.formatter, this.options, options);
89
+ if (this.options.style === 'percent' && ((this.options.minimumFractionDigits ?? 0) > 18 || (this.options.maximumFractionDigits ?? 0) > 18)) console.warn('NumberParser cannot handle percentages with greater than 18 decimal places, please reduce the number in your options.');
90
+ }
74
91
  parse(value) {
92
+ let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;
75
93
  // 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'
76
94
  let fullySanitizedValue = this.sanitize(value);
77
- if (this.symbols.group) // Remove group characters, and replace decimal points and numerals with ASCII values.
78
- fullySanitizedValue = $6c7bd7858deea686$var$replaceAll(fullySanitizedValue, this.symbols.group, '');
95
+ // Return NaN if there is a group symbol but useGrouping is false
96
+ if (!isGroupSymbolAllowed && this.symbols.group && fullySanitizedValue.includes(this.symbols.group)) return NaN;
97
+ else if (this.symbols.group) fullySanitizedValue = fullySanitizedValue.replaceAll(this.symbols.group, '');
79
98
  if (this.symbols.decimal) fullySanitizedValue = fullySanitizedValue.replace(this.symbols.decimal, '.');
80
99
  if (this.symbols.minusSign) fullySanitizedValue = fullySanitizedValue.replace(this.symbols.minusSign, '-');
81
100
  fullySanitizedValue = fullySanitizedValue.replace(this.symbols.numeral, this.symbols.index);
@@ -96,22 +115,24 @@ class $6c7bd7858deea686$var$NumberParserImpl {
96
115
  let newValue = fullySanitizedValue ? +fullySanitizedValue : NaN;
97
116
  if (isNaN(newValue)) return NaN;
98
117
  if (this.options.style === 'percent') {
99
- var _this_options_minimumFractionDigits, _this_options_maximumFractionDigits;
100
118
  // extra step for rounding percents to what our formatter would output
101
119
  let options = {
102
120
  ...this.options,
103
121
  style: 'decimal',
104
- minimumFractionDigits: Math.min(((_this_options_minimumFractionDigits = this.options.minimumFractionDigits) !== null && _this_options_minimumFractionDigits !== void 0 ? _this_options_minimumFractionDigits : 0) + 2, 20),
105
- maximumFractionDigits: Math.min(((_this_options_maximumFractionDigits = this.options.maximumFractionDigits) !== null && _this_options_maximumFractionDigits !== void 0 ? _this_options_maximumFractionDigits : 0) + 2, 20)
122
+ minimumFractionDigits: Math.min((this.options.minimumFractionDigits ?? 0) + 2, 20),
123
+ maximumFractionDigits: Math.min((this.options.maximumFractionDigits ?? 0) + 2, 20)
106
124
  };
107
- return new $6c7bd7858deea686$export$cd11ab140839f11d(this.locale, options).parse(new (0, $488c6ddbf4ef74c2$export$cc77c4ff7e8673c5)(this.locale, options).format(newValue));
125
+ return new $eb76cf4feb040f77$export$cd11ab140839f11d(this.locale, options).parse(new (0, $1dfb119a85e764e5$export$cc77c4ff7e8673c5)(this.locale, options).format(newValue));
108
126
  }
109
127
  // 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
110
- if (this.options.currencySign === 'accounting' && $6c7bd7858deea686$var$CURRENCY_SIGN_REGEX.test(value)) newValue = -1 * newValue;
128
+ if (this.options.currencySign === 'accounting' && $eb76cf4feb040f77$var$CURRENCY_SIGN_REGEX.test(value)) newValue = -1 * newValue;
111
129
  return newValue;
112
130
  }
113
131
  sanitize(value) {
114
- // Remove literals and whitespace, which are allowed anywhere in the string
132
+ let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;
133
+ // 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
134
+ // return the known value for that case.
135
+ if (this.symbols.noNumeralUnits.length > 0 && this.symbols.noNumeralUnits.find((obj)=>obj.unit === value)) return this.symbols.noNumeralUnits.find((obj)=>obj.unit === value).value.toString();
115
136
  value = value.replace(this.symbols.literals, '');
116
137
  // Replace the ASCII minus sign with the minus sign used in the current locale
117
138
  // so that both are allowed in case the user's keyboard doesn't have the locale's minus sign.
@@ -120,58 +141,39 @@ class $6c7bd7858deea686$var$NumberParserImpl {
120
141
  // instead they use the , (44) character or apparently the (1548) character.
121
142
  if (this.options.numberingSystem === 'arab') {
122
143
  if (this.symbols.decimal) {
123
- value = value.replace(',', this.symbols.decimal);
124
- value = value.replace(String.fromCharCode(1548), this.symbols.decimal);
144
+ value = $eb76cf4feb040f77$var$replaceAll(value, ',', this.symbols.decimal);
145
+ value = $eb76cf4feb040f77$var$replaceAll(value, String.fromCharCode(1548), this.symbols.decimal);
125
146
  }
126
- if (this.symbols.group) value = $6c7bd7858deea686$var$replaceAll(value, '.', this.symbols.group);
147
+ if (this.symbols.group && isGroupSymbolAllowed) value = $eb76cf4feb040f77$var$replaceAll(value, '.', this.symbols.group);
127
148
  }
128
149
  // In some locale styles, such as swiss currency, the group character can be a special single quote
129
150
  // that keyboards don't typically have. This expands the character to include the easier to type single quote.
130
- if (this.symbols.group === "\u2019" && value.includes("'")) value = $6c7bd7858deea686$var$replaceAll(value, "'", this.symbols.group);
151
+ if (this.symbols.group === "\u2019" && value.includes("'") && isGroupSymbolAllowed) value = $eb76cf4feb040f77$var$replaceAll(value, "'", this.symbols.group);
131
152
  // fr-FR group character is narrow non-breaking space, char code 8239 (U+202F), but that's not a key on the french keyboard,
132
153
  // so allow space and non-breaking space as a group char as well
133
- if (this.options.locale === 'fr-FR' && this.symbols.group) {
134
- value = $6c7bd7858deea686$var$replaceAll(value, ' ', this.symbols.group);
135
- value = $6c7bd7858deea686$var$replaceAll(value, /\u00A0/g, this.symbols.group);
154
+ if (this.options.locale === 'fr-FR' && this.symbols.group && isGroupSymbolAllowed) {
155
+ value = $eb76cf4feb040f77$var$replaceAll(value, ' ', this.symbols.group);
156
+ value = $eb76cf4feb040f77$var$replaceAll(value, /\u00A0/g, this.symbols.group);
136
157
  }
137
158
  return value;
138
159
  }
139
160
  isValidPartialNumber(value, minValue = -Infinity, maxValue = Infinity) {
161
+ let isGroupSymbolAllowed = this.formatter.resolvedOptions().useGrouping;
140
162
  value = this.sanitize(value);
141
163
  // Remove minus or plus sign, which must be at the start of the string.
142
164
  if (this.symbols.minusSign && value.startsWith(this.symbols.minusSign) && minValue < 0) value = value.slice(this.symbols.minusSign.length);
143
165
  else if (this.symbols.plusSign && value.startsWith(this.symbols.plusSign) && maxValue > 0) value = value.slice(this.symbols.plusSign.length);
144
- // Numbers cannot start with a group separator
145
- if (this.symbols.group && value.startsWith(this.symbols.group)) return false;
146
166
  // Numbers that can't have any decimal values fail if a decimal character is typed
147
167
  if (this.symbols.decimal && value.indexOf(this.symbols.decimal) > -1 && this.options.maximumFractionDigits === 0) return false;
148
168
  // Remove numerals, groups, and decimals
149
- if (this.symbols.group) value = $6c7bd7858deea686$var$replaceAll(value, this.symbols.group, '');
169
+ if (this.symbols.group && isGroupSymbolAllowed) value = $eb76cf4feb040f77$var$replaceAll(value, this.symbols.group, '');
150
170
  value = value.replace(this.symbols.numeral, '');
151
171
  if (this.symbols.decimal) value = value.replace(this.symbols.decimal, '');
152
172
  // The number is valid if there are no remaining characters
153
173
  return value.length === 0;
154
174
  }
155
- constructor(locale, options = {}){
156
- this.locale = locale;
157
- // see https://tc39.es/ecma402/#sec-setnfdigitoptions, when using roundingIncrement, the maximumFractionDigits and minimumFractionDigits must be equal
158
- // by default, they are 0 and 3 respectively, so we set them to 0 if neither are set
159
- if (options.roundingIncrement !== 1 && options.roundingIncrement != null) {
160
- if (options.maximumFractionDigits == null && options.minimumFractionDigits == null) {
161
- options.maximumFractionDigits = 0;
162
- options.minimumFractionDigits = 0;
163
- } else if (options.maximumFractionDigits == null) options.maximumFractionDigits = options.minimumFractionDigits;
164
- else if (options.minimumFractionDigits == null) options.minimumFractionDigits = options.maximumFractionDigits;
165
- // if both are specified, let the normal Range Error be thrown
166
- }
167
- this.formatter = new Intl.NumberFormat(locale, options);
168
- this.options = this.formatter.resolvedOptions();
169
- this.symbols = $6c7bd7858deea686$var$getSymbols(locale, this.formatter, this.options, options);
170
- var _this_options_minimumFractionDigits, _this_options_maximumFractionDigits;
171
- if (this.options.style === 'percent' && (((_this_options_minimumFractionDigits = this.options.minimumFractionDigits) !== null && _this_options_minimumFractionDigits !== void 0 ? _this_options_minimumFractionDigits : 0) > 18 || ((_this_options_maximumFractionDigits = this.options.maximumFractionDigits) !== null && _this_options_maximumFractionDigits !== void 0 ? _this_options_maximumFractionDigits : 0) > 18)) console.warn('NumberParser cannot handle percentages with greater than 18 decimal places, please reduce the number in your options.');
172
- }
173
175
  }
174
- const $6c7bd7858deea686$var$nonLiteralParts = new Set([
176
+ const $eb76cf4feb040f77$var$nonLiteralParts = new Set([
175
177
  'decimal',
176
178
  'fraction',
177
179
  'integer',
@@ -182,7 +184,7 @@ const $6c7bd7858deea686$var$nonLiteralParts = new Set([
182
184
  // This list is derived from https://www.unicode.org/cldr/charts/43/supplemental/language_plural_rules.html#comparison and includes
183
185
  // all unique numbers which we need to check in order to determine all the plural forms for a given locale.
184
186
  // See: https://github.com/adobe/react-spectrum/pull/5134/files#r1337037855 for used script
185
- const $6c7bd7858deea686$var$pluralNumbers = [
187
+ const $eb76cf4feb040f77$var$pluralNumbers = [
186
188
  0,
187
189
  4,
188
190
  2,
@@ -196,8 +198,7 @@ const $6c7bd7858deea686$var$pluralNumbers = [
196
198
  0.1,
197
199
  1.1
198
200
  ];
199
- function $6c7bd7858deea686$var$getSymbols(locale, formatter, intlOptions, originalOptions) {
200
- var _allParts_find, _posAllParts_find, _decimalParts_find, _allParts_find1;
201
+ function $eb76cf4feb040f77$var$getSymbols(locale, formatter, intlOptions, originalOptions) {
201
202
  // formatter needs access to all decimal places in order to generate the correct literal strings for the plural set
202
203
  let symbolFormatter = new Intl.NumberFormat(locale, {
203
204
  ...intlOptions,
@@ -206,18 +207,27 @@ function $6c7bd7858deea686$var$getSymbols(locale, formatter, intlOptions, origin
206
207
  maximumSignificantDigits: 21,
207
208
  roundingIncrement: 1,
208
209
  roundingPriority: 'auto',
209
- roundingMode: 'halfExpand'
210
+ roundingMode: 'halfExpand',
211
+ useGrouping: true
210
212
  });
211
213
  // Note: some locale's don't add a group symbol until there is a ten thousands place
212
214
  let allParts = symbolFormatter.formatToParts(-10000.111);
213
215
  let posAllParts = symbolFormatter.formatToParts(10000.111);
214
- let pluralParts = $6c7bd7858deea686$var$pluralNumbers.map((n)=>symbolFormatter.formatToParts(n));
215
- var _allParts_find_value;
216
- let minusSign = (_allParts_find_value = (_allParts_find = allParts.find((p)=>p.type === 'minusSign')) === null || _allParts_find === void 0 ? void 0 : _allParts_find.value) !== null && _allParts_find_value !== void 0 ? _allParts_find_value : '-';
217
- let plusSign = (_posAllParts_find = posAllParts.find((p)=>p.type === 'plusSign')) === null || _posAllParts_find === void 0 ? void 0 : _posAllParts_find.value;
216
+ let pluralParts = $eb76cf4feb040f77$var$pluralNumbers.map((n)=>symbolFormatter.formatToParts(n));
217
+ // if the plural parts include a unit but no integer or fraction, then we need to add the unit to the special set
218
+ let noNumeralUnits = pluralParts.map((p, i)=>{
219
+ let unit = p.find((p)=>p.type === 'unit');
220
+ if (unit && !p.some((p)=>p.type === 'integer' || p.type === 'fraction')) return {
221
+ unit: unit.value,
222
+ value: $eb76cf4feb040f77$var$pluralNumbers[i]
223
+ };
224
+ return null;
225
+ }).filter((p)=>!!p);
226
+ let minusSign = allParts.find((p)=>p.type === 'minusSign')?.value ?? '-';
227
+ let plusSign = posAllParts.find((p)=>p.type === 'plusSign')?.value;
218
228
  // Safari does not support the signDisplay option, but our number parser polyfills it.
219
229
  // If no plus sign was returned, but the original options contained signDisplay, default to the '+' character.
220
- if (!plusSign && ((originalOptions === null || originalOptions === void 0 ? void 0 : originalOptions.signDisplay) === 'exceptZero' || (originalOptions === null || originalOptions === void 0 ? void 0 : originalOptions.signDisplay) === 'always')) plusSign = '+';
230
+ if (!plusSign && (originalOptions?.signDisplay === 'exceptZero' || originalOptions?.signDisplay === 'always')) plusSign = '+';
221
231
  // If maximumSignificantDigits is 1 (the minimum) then we won't get decimal characters out of the above formatters
222
232
  // Percent also defaults to 0 fractionDigits, so we need to make a new one that isn't percent to get an accurate decimal
223
233
  let decimalParts = new Intl.NumberFormat(locale, {
@@ -225,19 +235,20 @@ function $6c7bd7858deea686$var$getSymbols(locale, formatter, intlOptions, origin
225
235
  minimumFractionDigits: 2,
226
236
  maximumFractionDigits: 2
227
237
  }).formatToParts(0.001);
228
- let decimal = (_decimalParts_find = decimalParts.find((p)=>p.type === 'decimal')) === null || _decimalParts_find === void 0 ? void 0 : _decimalParts_find.value;
229
- let group = (_allParts_find1 = allParts.find((p)=>p.type === 'group')) === null || _allParts_find1 === void 0 ? void 0 : _allParts_find1.value;
238
+ let decimal = decimalParts.find((p)=>p.type === 'decimal')?.value;
239
+ let group = allParts.find((p)=>p.type === 'group')?.value;
230
240
  // this set is also for a regex, it's all literals that might be in the string we want to eventually parse that
231
241
  // don't contribute to the numerical value
232
- let allPartsLiterals = allParts.filter((p)=>!$6c7bd7858deea686$var$nonLiteralParts.has(p.type)).map((p)=>$6c7bd7858deea686$var$escapeRegex(p.value));
233
- let pluralPartsLiterals = pluralParts.flatMap((p)=>p.filter((p)=>!$6c7bd7858deea686$var$nonLiteralParts.has(p.type)).map((p)=>$6c7bd7858deea686$var$escapeRegex(p.value)));
242
+ let allPartsLiterals = allParts.filter((p)=>!$eb76cf4feb040f77$var$nonLiteralParts.has(p.type)).map((p)=>$eb76cf4feb040f77$var$escapeRegex(p.value));
243
+ let pluralPartsLiterals = pluralParts.flatMap((p)=>p.filter((p)=>!$eb76cf4feb040f77$var$nonLiteralParts.has(p.type)).map((p)=>$eb76cf4feb040f77$var$escapeRegex(p.value)));
234
244
  let sortedLiterals = [
235
245
  ...new Set([
236
246
  ...allPartsLiterals,
237
247
  ...pluralPartsLiterals
238
248
  ])
239
249
  ].sort((a, b)=>b.length - a.length);
240
- let literals = sortedLiterals.length === 0 ? new RegExp('[\\p{White_Space}]', 'gu') : new RegExp(`${sortedLiterals.join('|')}|[\\p{White_Space}]`, 'gu');
250
+ // Match both whitespace and formatting characters
251
+ let literals = sortedLiterals.length === 0 ? new RegExp('\\p{White_Space}|\\p{Cf}', 'gu') : new RegExp(`${sortedLiterals.join('|')}|\\p{White_Space}|\\p{Cf}`, 'gu');
241
252
  // These are for replacing non-latn characters with the latn equivalent
242
253
  let numerals = [
243
254
  ...new Intl.NumberFormat(intlOptions.locale, {
@@ -257,17 +268,19 @@ function $6c7bd7858deea686$var$getSymbols(locale, formatter, intlOptions, origin
257
268
  group: group,
258
269
  literals: literals,
259
270
  numeral: numeral,
260
- index: index
271
+ numerals: numerals,
272
+ index: index,
273
+ noNumeralUnits: noNumeralUnits
261
274
  };
262
275
  }
263
- function $6c7bd7858deea686$var$replaceAll(str, find, replace) {
276
+ function $eb76cf4feb040f77$var$replaceAll(str, find, replace) {
264
277
  if (str.replaceAll) return str.replaceAll(find, replace);
265
278
  return str.split(find).join(replace);
266
279
  }
267
- function $6c7bd7858deea686$var$escapeRegex(string) {
280
+ function $eb76cf4feb040f77$var$escapeRegex(string) {
268
281
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
269
282
  }
270
283
 
271
284
 
272
- export {$6c7bd7858deea686$export$cd11ab140839f11d as NumberParser};
273
- //# sourceMappingURL=NumberParser.module.js.map
285
+ export {$eb76cf4feb040f77$export$cd11ab140839f11d as NumberParser};
286
+ //# sourceMappingURL=NumberParser.mjs.map
@@ -0,0 +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"}
@@ -0,0 +1,28 @@
1
+ export interface NumberFormatOptions extends Intl.NumberFormatOptions {
2
+ /** Overrides default numbering system for the current locale. */
3
+ numberingSystem?: string;
4
+ }
5
+ interface NumberRangeFormatPart extends Intl.NumberFormatPart {
6
+ source: 'startRange' | 'endRange' | 'shared';
7
+ }
8
+ /**
9
+ * A wrapper around Intl.NumberFormat providing additional options, polyfills, and caching for performance.
10
+ */
11
+ export declare class NumberFormatter implements Intl.NumberFormat {
12
+ private numberFormatter;
13
+ private options;
14
+ constructor(locale: string, options?: NumberFormatOptions);
15
+ /** Formats a number value as a string, according to the locale and options provided to the constructor. */
16
+ format(value: number): string;
17
+ /** Formats a number to an array of parts such as separators, digits, punctuation, and more. */
18
+ formatToParts(value: number): Intl.NumberFormatPart[];
19
+ /** Formats a number range as a string. */
20
+ formatRange(start: number, end: number): string;
21
+ /** Formats a number range as an array of parts. */
22
+ formatRangeToParts(start: number, end: number): NumberRangeFormatPart[];
23
+ /** Returns the resolved formatting options based on the values passed to the constructor. */
24
+ resolvedOptions(): Intl.ResolvedNumberFormatOptions;
25
+ }
26
+ /** @private - exported for tests */
27
+ export declare function numberFormatSignDisplayPolyfill(numberFormat: Intl.NumberFormat, signDisplay: string, num: number): string;
28
+ export {};
@@ -0,0 +1,27 @@
1
+ /**
2
+ * A NumberParser can be used to perform locale-aware parsing of numbers from Unicode strings,
3
+ * as well as validation of partial user input. It automatically detects the numbering system
4
+ * used in the input, and supports parsing decimals, percentages, currency values, and units
5
+ * according to the locale.
6
+ */
7
+ export declare class NumberParser {
8
+ private locale;
9
+ private options;
10
+ constructor(locale: string, options?: Intl.NumberFormatOptions);
11
+ /**
12
+ * Parses the given string to a number. Returns NaN if a valid number could not be parsed.
13
+ */
14
+ parse(value: string): number;
15
+ /**
16
+ * Returns whether the given string could potentially be a valid number. This should be used to
17
+ * validate user input as the user types. If a `minValue` or `maxValue` is provided, the validity
18
+ * of the minus/plus sign characters can be checked.
19
+ */
20
+ isValidPartialNumber(value: string, minValue?: number, maxValue?: number): boolean;
21
+ /**
22
+ * Returns a numbering system for which the given string is valid in the current locale.
23
+ * If no numbering system could be detected, the default numbering system for the current
24
+ * locale is returned.
25
+ */
26
+ getNumberingSystem(value: string): string;
27
+ }
@@ -0,0 +1,3 @@
1
+ export type { NumberFormatOptions } from './NumberFormatter';
2
+ export { NumberFormatter } from './NumberFormatter';
3
+ export { NumberParser } from './NumberParser';
package/package.json CHANGED
@@ -1,20 +1,18 @@
1
1
  {
2
2
  "name": "@internationalized/number",
3
- "version": "3.6.5",
3
+ "version": "3.6.6",
4
4
  "description": "Internationalized number formatting and parsing utilities",
5
5
  "license": "Apache-2.0",
6
- "main": "dist/main.js",
7
- "module": "dist/module.js",
6
+ "main": "dist/index.cjs",
7
+ "module": "dist/index.js",
8
+ "import": "dist/index.mjs",
8
9
  "exports": {
9
10
  "source": "./src/index.ts",
10
- "types": [
11
- "./dist/types.d.ts",
12
- "./src/index.ts"
13
- ],
14
- "import": "./dist/import.mjs",
15
- "require": "./dist/main.js"
11
+ "types": "./dist/types/src/index.d.ts",
12
+ "import": "./dist/index.mjs",
13
+ "require": "./dist/index.cjs"
16
14
  },
17
- "types": "dist/types.d.ts",
15
+ "types": "./dist/types/src/index.d.ts",
18
16
  "source": "src/index.ts",
19
17
  "files": [
20
18
  "dist",
@@ -31,5 +29,22 @@
31
29
  "publishConfig": {
32
30
  "access": "public"
33
31
  },
34
- "gitHead": "2c58ed3ddd9be9100af9b1d0cfd137fcdc95ba2d"
32
+ "targets": {
33
+ "types": false,
34
+ "module": {
35
+ "engines": {
36
+ "browsers": [
37
+ "chrome >= 79",
38
+ "firefox >= 85",
39
+ "safari >= 13"
40
+ ]
41
+ }
42
+ },
43
+ "import": {
44
+ "isLibrary": true,
45
+ "outputFormat": "esmodule",
46
+ "includeNodeModules": false
47
+ }
48
+ },
49
+ "gitHead": "a6999bdf494a2e9c0381a5881908328bdd22ddae"
35
50
  }