Skip to content

Commit f7ddf1b

Browse files
authored
Move number parser to stately, and refactor controlled selection behavior (adobe#1487)
* Move number parser to stately, and refactor controlled selection behavior * Fix parsing currency symbols with valid number characters and add number parser tests * Prevent invalid deletions, e.g. inside currency symbol
1 parent 5faa915 commit f7ddf1b

24 files changed

+931
-579
lines changed

packages/@react-aria/i18n/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"@babel/runtime": "^7.6.2",
2121
"@react-aria/ssr": "^3.0.1",
2222
"@react-aria/utils": "^3.4.0",
23+
"@react-stately/i18n": "3.0.0-alpha.1",
2324
"@react-types/shared": "^3.3.0",
2425
"intl-messageformat": "^2.2.0"
2526
},

packages/@react-aria/i18n/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
export * from './context';
1616
export * from './useMessageFormatter';
1717
export * from './useDateFormatter';
18-
export * from './useNumberParser';
1918
export * from './useNumberFormatter';
2019
export * from './useCollator';
2120
export * from './useFilter';

packages/@react-aria/i18n/src/useNumberFormatter.ts

Lines changed: 2 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,54 +10,15 @@
1010
* governing permissions and limitations under the License.
1111
*/
1212

13-
import {numberFormatSignDisplayPolyfill} from './utils';
13+
import {getNumberFormatter, NumberFormatOptions} from '@react-stately/i18n';
1414
import {useLocale} from './context';
1515

16-
let formatterCache = new Map<string, Intl.NumberFormat>();
17-
18-
let supportsSignDisplay = false;
19-
try {
20-
// @ts-ignore
21-
supportsSignDisplay = (new Intl.NumberFormat('de-DE', {signDisplay: 'exceptZero'})).resolvedOptions().signDisplay === 'exceptZero';
22-
// eslint-disable-next-line no-empty
23-
} catch (e) {}
24-
25-
export type NumeralSystem = 'arab' | 'hanidec' | 'latn';
26-
27-
export interface NumberFormatOptions extends Intl.NumberFormatOptions {
28-
/** Overrides the CLDR or browser default numeral system for the current locale. */
29-
numeralSystem?: NumeralSystem
30-
}
31-
3216
/**
3317
* Provides localized number formatting for the current locale. Automatically updates when the locale changes,
3418
* and handles caching of the number formatter for performance.
3519
* @param options - Formatting options.
3620
*/
3721
export function useNumberFormatter(options: NumberFormatOptions = {}): Intl.NumberFormat {
38-
let {numeralSystem} = options;
3922
let {locale} = useLocale();
40-
41-
if (numeralSystem && locale.indexOf('-u-nu-') === -1) {
42-
locale = `${locale}-u-nu-${numeralSystem}`;
43-
}
44-
45-
let cacheKey = locale + (options ? Object.entries(options).sort((a, b) => a[0] < b[0] ? -1 : 1).join() : '');
46-
if (formatterCache.has(cacheKey)) {
47-
return formatterCache.get(cacheKey);
48-
}
49-
50-
let numberFormatter = new Intl.NumberFormat(locale, options);
51-
// @ts-ignore
52-
let {signDisplay} = options || {};
53-
formatterCache.set(cacheKey, (!supportsSignDisplay && signDisplay != null) ? new Proxy(numberFormatter, {
54-
get(target, property) {
55-
if (property === 'format') {
56-
return (v) => numberFormatSignDisplayPolyfill(numberFormatter, signDisplay, v);
57-
} else {
58-
return target[property];
59-
}
60-
}
61-
}) : numberFormatter);
62-
return numberFormatter;
23+
return getNumberFormatter(locale, options);
6324
}

packages/@react-aria/i18n/src/useNumberParser.ts

Lines changed: 0 additions & 207 deletions
This file was deleted.

packages/@react-aria/i18n/src/utils.ts

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -31,36 +31,3 @@ export function isRTL(locale: string) {
3131
let lang = locale.split('-')[0];
3232
return RTL_LANGS.has(lang);
3333
}
34-
35-
export function numberFormatSignDisplayPolyfill(numberFormat: Intl.NumberFormat, signDisplay: 'always' | 'exceptZero' | 'auto' | 'never', num: number) {
36-
if (signDisplay === 'auto') {
37-
return numberFormat.format(num);
38-
} else if (signDisplay === 'never') {
39-
return numberFormat.format(Math.abs(num));
40-
} else {
41-
let needsPositiveSign = false;
42-
if (signDisplay === 'always') {
43-
needsPositiveSign = num > 0 || Object.is(num, 0);
44-
} else if (signDisplay === 'exceptZero') {
45-
if (Object.is(num, -0) || Object.is(num, 0)) {
46-
num = Math.abs(num);
47-
} else {
48-
needsPositiveSign = num > 0;
49-
}
50-
}
51-
52-
if (needsPositiveSign) {
53-
let negative = numberFormat.format(-num);
54-
let noSign = numberFormat.format(num);
55-
// ignore RTL/LTR marker character
56-
let minus = negative.replace(noSign, '').replace(/\u200e|\u061C/, '');
57-
if ([...minus].length !== 1) {
58-
console.warn('@react-aria/i18n polyfill for NumberFormat signDisplay: Unsupported case');
59-
}
60-
let positive = negative.replace(noSign, '!!!').replace(minus, '+').replace('!!!', noSign);
61-
return positive;
62-
} else {
63-
return numberFormat.format(num);
64-
}
65-
}
66-
}

packages/@react-aria/numberfield/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"@react-aria/spinbutton": "^3.0.0-alpha.1",
2626
"@react-aria/textfield": "^3.1.0",
2727
"@react-aria/utils": "^3.1.0",
28+
"@react-stately/i18n": "3.0.0-alpha.1",
2829
"@react-stately/numberfield": "3.0.0-alpha.1",
2930
"@react-types/button": "^3.1.0",
3031
"@react-types/numberfield": "^3.0.0-alpha.1",

0 commit comments

Comments
 (0)