UNPKG

8.09 kBJavaScriptView Raw
1"use strict";
2/*
3 * Copyright 2018 Palantir Technologies, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17Object.defineProperty(exports, "__esModule", { value: true });
18exports.sanitizeNumericInput = exports.toMaxPrecision = exports.isValidNumericKeyboardEvent = exports.isValueNumeric = exports.parseStringToStringNumber = exports.getValueOrEmptyValue = exports.clampValue = exports.toLocaleString = void 0;
19var utils_1 = require("../../common/utils");
20/** Returns the `decimal` number separator based on locale */
21function getDecimalSeparator(locale) {
22 var testNumber = 1.9;
23 var testText = testNumber.toLocaleString(locale);
24 var one = (1).toLocaleString(locale);
25 var nine = (9).toLocaleString(locale);
26 var pattern = "".concat(one, "(.+)").concat(nine);
27 var result = new RegExp(pattern).exec(testText);
28 return (result && result[1]) || ".";
29}
30function toLocaleString(num, locale) {
31 if (locale === void 0) { locale = "en-US"; }
32 return sanitizeNumericInput(num.toLocaleString(locale), locale);
33}
34exports.toLocaleString = toLocaleString;
35function clampValue(value, min, max) {
36 // defaultProps won't work if the user passes in null, so just default
37 // to +/- infinity here instead, as a catch-all.
38 var adjustedMin = min != null ? min : -Infinity;
39 var adjustedMax = max != null ? max : Infinity;
40 return (0, utils_1.clamp)(value, adjustedMin, adjustedMax);
41}
42exports.clampValue = clampValue;
43function getValueOrEmptyValue(value) {
44 if (value === void 0) { value = ""; }
45 return value.toString();
46}
47exports.getValueOrEmptyValue = getValueOrEmptyValue;
48/** Transform the localized character (ex. "") to a javascript recognizable string number (ex. "10.99") */
49function transformLocalizedNumberToStringNumber(character, locale) {
50 var charactersMap = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(function (value) { return value.toLocaleString(locale); });
51 var jsNumber = charactersMap.indexOf(character);
52 if (jsNumber !== -1) {
53 return jsNumber;
54 }
55 else {
56 return character;
57 }
58}
59/** Transforms the localized number (ex. "10,99") to a javascript recognizable string number (ex. "10.99") */
60function parseStringToStringNumber(value, locale) {
61 var valueAsString = "" + value;
62 if (parseFloat(valueAsString).toString() === value.toString()) {
63 return value.toString();
64 }
65 if (locale !== undefined) {
66 var decimalSeparator = getDecimalSeparator(locale);
67 var sanitizedString = sanitizeNumericInput(valueAsString, locale);
68 return sanitizedString
69 .split("")
70 .map(function (character) { return transformLocalizedNumberToStringNumber(character, locale); })
71 .join("")
72 .replace(decimalSeparator, ".");
73 }
74 return value.toString();
75}
76exports.parseStringToStringNumber = parseStringToStringNumber;
77/** Returns `true` if the string represents a valid numeric value, like "1e6". */
78function isValueNumeric(value, locale) {
79 // checking if a string is numeric in Typescript is a big pain, because
80 // we can't simply toss a string parameter to isFinite. below is the
81 // essential approach that jQuery uses, which involves subtracting a
82 // parsed numeric value from the string representation of the value. we
83 // need to cast the value to the `any` type to allow this operation
84 // between dissimilar types.
85 var stringToStringNumber = parseStringToStringNumber(value, locale);
86 return value != null && stringToStringNumber - parseFloat(stringToStringNumber) + 1 >= 0;
87}
88exports.isValueNumeric = isValueNumeric;
89function isValidNumericKeyboardEvent(e, locale) {
90 // unit tests may not include e.key. don't bother disabling those events.
91 if (e.key == null) {
92 return true;
93 }
94 // allow modified key strokes that may involve letters and other
95 // non-numeric/invalid characters (Cmd + A, Cmd + C, Cmd + V, Cmd + X).
96 if (e.ctrlKey || e.altKey || e.metaKey) {
97 return true;
98 }
99 // keys that print a single character when pressed have a `key` name of
100 // length 1. every other key has a longer `key` name (e.g. "Backspace",
101 // "ArrowUp", "Shift"). since none of those keys can print a character
102 // to the field--and since they may have important native behaviors
103 // beyond printing a character--we don't want to disable their effects.
104 var isSingleCharKey = e.key.length === 1;
105 if (!isSingleCharKey) {
106 return true;
107 }
108 // now we can simply check that the single character that wants to be printed
109 // is a floating-point number character that we're allowed to print.
110 return isFloatingPointNumericCharacter(e.key, locale);
111}
112exports.isValidNumericKeyboardEvent = isValidNumericKeyboardEvent;
113/**
114 * A regex that matches a string of length 1 (i.e. a standalone character)
115 * if and only if it is a floating-point number character as defined by W3C:
116 * https://www.w3.org/TR/2012/WD-html-markup-20120329/datatypes.html#common.data.float
117 *
118 * Floating-point number characters are the only characters that can be
119 * printed within a default input[type="number"]. This component should
120 * behave the same way when this.props.allowNumericCharactersOnly = true.
121 * See here for the input[type="number"].value spec:
122 * https://www.w3.org/TR/2012/WD-html-markup-20120329/input.number.html#input.number.attrs.value
123 */
124function isFloatingPointNumericCharacter(character, locale) {
125 if (locale !== undefined) {
126 var decimalSeparator = getDecimalSeparator(locale).replace(".", "\\.");
127 var numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(function (value) { return value.toLocaleString(locale); }).join("");
128 var localeFloatingPointNumericCharacterRegex = new RegExp("^[Ee" + numbers + "\\+\\-" + decimalSeparator + "]$");
129 return localeFloatingPointNumericCharacterRegex.test(character);
130 }
131 else {
132 var floatingPointNumericCharacterRegex = /^[Ee0-9\+\-\.]$/;
133 return floatingPointNumericCharacterRegex.test(character);
134 }
135}
136/**
137 * Round the value to have _up to_ the specified maximum precision.
138 *
139 * This differs from `toFixed(5)` in that trailing zeroes are not added on
140 * more precise values, resulting in shorter strings.
141 */
142function toMaxPrecision(value, maxPrecision) {
143 // round the value to have the specified maximum precision (toFixed is the wrong choice,
144 // because it would show trailing zeros in the decimal part out to the specified precision)
145 // source: http://stackoverflow.com/a/18358056/5199574
146 var scaleFactor = Math.pow(10, maxPrecision);
147 return Math.round(value * scaleFactor) / scaleFactor;
148}
149exports.toMaxPrecision = toMaxPrecision;
150/**
151 * Convert Japanese full-width numbers, e.g. '5', to ASCII, e.g. '5'
152 * This should be called before performing any other numeric string input validation.
153 */
154function convertFullWidthNumbersToAscii(value) {
155 return value.replace(/[\uFF10-\uFF19]/g, function (m) { return String.fromCharCode(m.charCodeAt(0) - 0xfee0); });
156}
157/**
158 * Convert full-width (Japanese) numbers to ASCII, and strip all characters that are not valid floating-point numeric characters
159 */
160function sanitizeNumericInput(value, locale) {
161 var valueChars = convertFullWidthNumbersToAscii(value).split("");
162 var sanitizedValueChars = valueChars.filter(function (valueChar) { return isFloatingPointNumericCharacter(valueChar, locale); });
163 return sanitizedValueChars.join("");
164}
165exports.sanitizeNumericInput = sanitizeNumericInput;
166//# sourceMappingURL=numericInputUtils.js.map
\No newline at end of file