@servicetitan/anvil2 1.43.3 → 1.44.0
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.
- package/CHANGELOG.md +8 -5
- package/dist/{Breadcrumbs-B5bqrZ5D-BqK-Qfh9.js → Breadcrumbs-BMbkH9hL-BUjQksuj.js} +3 -3
- package/dist/{Breadcrumbs-B5bqrZ5D-BqK-Qfh9.js.map → Breadcrumbs-BMbkH9hL-BUjQksuj.js.map} +1 -1
- package/dist/{Breadcrumbs-De8uoLi8.js → Breadcrumbs-fthw3qaL.js} +2 -2
- package/dist/{Breadcrumbs-De8uoLi8.js.map → Breadcrumbs-fthw3qaL.js.map} +1 -1
- package/dist/Breadcrumbs.js +1 -1
- package/dist/{Calendar-DD5kmVd3-CBGTR11R.js → Calendar-BvftKznl-D4_xp9Rv.js} +3 -3
- package/dist/{Calendar-DD5kmVd3-CBGTR11R.js.map → Calendar-BvftKznl-D4_xp9Rv.js.map} +1 -1
- package/dist/{Calendar-Bgpz99F2.js → Calendar-DdOR9T_K.js} +2 -2
- package/dist/{Calendar-Bgpz99F2.js.map → Calendar-DdOR9T_K.js.map} +1 -1
- package/dist/Calendar.js +1 -1
- package/dist/{DateField-_TqCdcYv.js → DateField-Bqsnpt8S.js} +4 -4
- package/dist/{DateField-_TqCdcYv.js.map → DateField-Bqsnpt8S.js.map} +1 -1
- package/dist/DateField.js +1 -1
- package/dist/{DateFieldRange-Dk8WA52F.js → DateFieldRange-Cax7Kl9A.js} +2 -2
- package/dist/{DateFieldRange-Dk8WA52F.js.map → DateFieldRange-Cax7Kl9A.js.map} +1 -1
- package/dist/DateFieldRange.js +1 -1
- package/dist/{DateFieldSingle-D3xD8YZk.js → DateFieldSingle-bMX770gU.js} +2 -2
- package/dist/{DateFieldSingle-D3xD8YZk.js.map → DateFieldSingle-bMX770gU.js.map} +1 -1
- package/dist/DateFieldSingle.js +1 -1
- package/dist/{DateFieldYearless-BxkCSNk5.js → DateFieldYearless-ClNYTBK_.js} +2 -2
- package/dist/{DateFieldYearless-BxkCSNk5.js.map → DateFieldYearless-ClNYTBK_.js.map} +1 -1
- package/dist/{DateFieldYearless-CAUHW6Ow-EUWxJ0OY.js → DateFieldYearless-pejtv7-x-DBHpW83U.js} +7 -65
- package/dist/DateFieldYearless-pejtv7-x-DBHpW83U.js.map +1 -0
- package/dist/DateFieldYearless.js +1 -1
- package/dist/{InputMask-wUro4G2j.js → InputMask-BOUlnmiF.js} +2 -2
- package/dist/{InputMask-wUro4G2j.js.map → InputMask-BOUlnmiF.js.map} +1 -1
- package/dist/{InputMask-CE3pdXwL-B8XVrj36.js → InputMask-BuO8lNAB-DdxdO5Jw.js} +3 -3
- package/dist/{InputMask-CE3pdXwL-B8XVrj36.js.map → InputMask-BuO8lNAB-DdxdO5Jw.js.map} +1 -1
- package/dist/InputMask.js +1 -1
- package/dist/{Link-DZa0wmkA.js → Link-C4N_cV3i.js} +2 -2
- package/dist/{Link-DZa0wmkA.js.map → Link-C4N_cV3i.js.map} +1 -1
- package/dist/{Link-Dqp_XXl_-Bv20l_tY.js → Link-MiffPrW9-Cx1zYWSF.js} +3 -3
- package/dist/{Link-Dqp_XXl_-Bv20l_tY.js.map → Link-MiffPrW9-Cx1zYWSF.js.map} +1 -1
- package/dist/Link.js +1 -1
- package/dist/LinkButton.css +5 -0
- package/dist/LinkButton.d.ts +6 -0
- package/dist/LinkButton.js +76 -0
- package/dist/LinkButton.js.map +1 -0
- package/dist/{ListView-DdHpJHTc.js → ListView-DVPhWDCM.js} +24 -5
- package/dist/ListView-DVPhWDCM.js.map +1 -0
- package/dist/ListView.js +1 -1
- package/dist/NumberField-C9lMsPMD.js +1582 -0
- package/dist/NumberField-C9lMsPMD.js.map +1 -0
- package/dist/NumberField.css +49 -0
- package/dist/NumberField.d.ts +6 -0
- package/dist/NumberField.js +2 -0
- package/dist/NumberField.js.map +1 -0
- package/dist/{Page-CxB5N9dR.js → Page-CGAylFKz.js} +2 -2
- package/dist/{Page-CxB5N9dR.js.map → Page-CGAylFKz.js.map} +1 -1
- package/dist/Page.js +1 -1
- package/dist/{SegmentedControl-DKMQuf7s.js → SegmentedControl-DY1PSYmd.js} +2 -2
- package/dist/{SegmentedControl-DKMQuf7s.js.map → SegmentedControl-DY1PSYmd.js.map} +1 -1
- package/dist/SegmentedControl.js +1 -1
- package/dist/{SelectCard-DUNwYa5y-BSi21Aba.js → SelectCard-LSAl_7Lh-BYtfe9PC.js} +3 -3
- package/dist/{SelectCard-DUNwYa5y-BSi21Aba.js.map → SelectCard-LSAl_7Lh-BYtfe9PC.js.map} +1 -1
- package/dist/SelectCard.js +1 -1
- package/dist/{SelectCardGroup-YGYiBv5M.js → SelectCardGroup-u_QKdeRZ.js} +2 -2
- package/dist/{SelectCardGroup-YGYiBv5M.js.map → SelectCardGroup-u_QKdeRZ.js.map} +1 -1
- package/dist/{TextField-gYAqTpcX.js → TextField-B364hxo8.js} +2 -2
- package/dist/{TextField-gYAqTpcX.js.map → TextField-B364hxo8.js.map} +1 -1
- package/dist/{TextField-CRTh0gL_-D2CjcYXX.js → TextField-DoPP1CQ--UWAOTYiv.js} +2 -2
- package/dist/{TextField-CRTh0gL_-D2CjcYXX.js.map → TextField-DoPP1CQ--UWAOTYiv.js.map} +1 -1
- package/dist/TextField.js +1 -1
- package/dist/{Textarea-DohNOiIp.js → Textarea-D2AAZ1L3.js} +2 -2
- package/dist/{Textarea-DohNOiIp.js.map → Textarea-D2AAZ1L3.js.map} +1 -1
- package/dist/Textarea.js +1 -1
- package/dist/{TimeField-DRHLRqN3.js → TimeField-tA9uo4lK.js} +5 -4
- package/dist/{TimeField-DRHLRqN3.js.map → TimeField-tA9uo4lK.js.map} +1 -1
- package/dist/TimeField.js +1 -1
- package/dist/assets/icons/st/gnav_home_outline.svg +1 -1
- package/dist/assets/icons/st.ts +0 -2
- package/dist/components/LinkButton/LinkButton.d.ts +57 -0
- package/dist/components/LinkButton/index.d.ts +2 -0
- package/dist/components/NumberField/NumberField.d.ts +11 -0
- package/dist/components/NumberField/index.d.ts +2 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/{usePopoverSupport-B9Lsqryr-DhZHMoNb.js → index.esm-dyoPQhi6.js} +735 -13
- package/dist/index.esm-dyoPQhi6.js.map +1 -0
- package/dist/index.js +17 -16
- package/dist/index.js.map +1 -1
- package/dist/useFocusWithin-Cxz14Zyz-DEudRcSI.js +64 -0
- package/dist/useFocusWithin-Cxz14Zyz-DEudRcSI.js.map +1 -0
- package/dist/useLinkStyles.js +1 -1
- package/dist/{useOptionallyControlledState-DAv5LXXh-DAv5LXXh.js → useOptionallyControlledState-DbDuos5L-DbDuos5L.js} +9 -3
- package/dist/useOptionallyControlledState-DbDuos5L-DbDuos5L.js.map +1 -0
- package/dist/usePopoverSupport-B9Lsqryr-CYJxXiun.js +15 -0
- package/dist/usePopoverSupport-B9Lsqryr-CYJxXiun.js.map +1 -0
- package/package.json +2 -2
- package/dist/DateFieldYearless-CAUHW6Ow-EUWxJ0OY.js.map +0 -1
- package/dist/ListView-DdHpJHTc.js.map +0 -1
- package/dist/assets/icons/st/ai_mark.svg +0 -1
- package/dist/assets/icons/st/ai_mark_gradient.svg +0 -1
- package/dist/useOptionallyControlledState-DAv5LXXh-DAv5LXXh.js.map +0 -1
- package/dist/usePopoverSupport-B9Lsqryr-DhZHMoNb.js.map +0 -1
- /package/dist/{Breadcrumbs-B5bqrZ5D.css → Breadcrumbs-BMbkH9hL.css} +0 -0
- /package/dist/{Calendar-DD5kmVd3.css → Calendar-BvftKznl.css} +0 -0
- /package/dist/{Link-Dqp_XXl_.css → Link-MiffPrW9.css} +0 -0
- /package/dist/{SelectCard-DUNwYa5y.css → SelectCard-LSAl_7Lh.css} +0 -0
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { useState, useCallback, useRef, useLayoutEffect, useEffect } from 'react';
|
|
2
|
-
import { s as supportsPopover } from './ProgressBar-BRvB-bD4-DppwBrFg.js';
|
|
3
2
|
|
|
4
3
|
function getContentEditableSelection(element) {
|
|
5
4
|
const { anchorOffset = 0, focusOffset = 0 } = element.ownerDocument.getSelection() || {};
|
|
@@ -972,6 +971,9 @@ const DATE_SEGMENTS_MAX_VALUES = {
|
|
|
972
971
|
year: 9999,
|
|
973
972
|
};
|
|
974
973
|
|
|
974
|
+
// eslint-disable-next-line i18n/no-russian-character
|
|
975
|
+
const DEFAULT_DECIMAL_PSEUDO_SEPARATORS = ['.', ',', 'б', 'ю'];
|
|
976
|
+
|
|
975
977
|
const DEFAULT_MIN_DATE = new Date('0001-01-01T00:00');
|
|
976
978
|
const DEFAULT_MAX_DATE = new Date('9999-12-31T23:59:59.999');
|
|
977
979
|
|
|
@@ -992,6 +994,10 @@ const DEFAULT_TIME_SEGMENT_MIN_VALUES = {
|
|
|
992
994
|
* {@link https://unicode-table.com/en/00A0/ Non-breaking space}.
|
|
993
995
|
*/
|
|
994
996
|
const CHAR_NO_BREAK_SPACE = '\u00A0';
|
|
997
|
+
/**
|
|
998
|
+
* {@link https://symbl.cc/en/200B/ Zero width space}.
|
|
999
|
+
*/
|
|
1000
|
+
const CHAR_ZERO_WIDTH_SPACE = '\u200B';
|
|
995
1001
|
/**
|
|
996
1002
|
* {@link https://unicode-table.com/en/2013/ EN dash}
|
|
997
1003
|
* is used to indicate a range of numbers or a span of time.
|
|
@@ -1119,6 +1125,21 @@ function escapeRegExp(str) {
|
|
|
1119
1125
|
: str;
|
|
1120
1126
|
}
|
|
1121
1127
|
|
|
1128
|
+
function extractAffixes(value, { prefix, postfix }) {
|
|
1129
|
+
var _a, _b;
|
|
1130
|
+
const prefixRegExp = new RegExp(`^${escapeRegExp(prefix)}`);
|
|
1131
|
+
const postfixRegExp = new RegExp(`${escapeRegExp(postfix)}$`);
|
|
1132
|
+
const [extractedPrefix = ''] = (_a = value.match(prefixRegExp)) !== null && _a !== void 0 ? _a : [];
|
|
1133
|
+
const [extractedPostfix = ''] = (_b = value.match(postfixRegExp)) !== null && _b !== void 0 ? _b : [];
|
|
1134
|
+
return {
|
|
1135
|
+
extractedPrefix,
|
|
1136
|
+
extractedPostfix,
|
|
1137
|
+
cleanValue: extractedPrefix || extractedPostfix
|
|
1138
|
+
? value.slice(extractedPrefix.length, extractedPostfix.length ? -extractedPostfix.length : Infinity)
|
|
1139
|
+
: value,
|
|
1140
|
+
};
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1122
1143
|
function findCommonBeginningSubstr(a, b) {
|
|
1123
1144
|
let res = '';
|
|
1124
1145
|
for (let i = 0; i < a.length; i++) {
|
|
@@ -2108,6 +2129,717 @@ function cutExpression(expression, value) {
|
|
|
2108
2129
|
return expression.slice(0, afterLastDigit);
|
|
2109
2130
|
}
|
|
2110
2131
|
|
|
2132
|
+
/**
|
|
2133
|
+
* It drops prefix and postfix from data
|
|
2134
|
+
* Needed for case, when prefix or postfix contain decimalSeparator, to ignore it in resulting number
|
|
2135
|
+
* @example User pastes '{prefix}123.45{postfix}' => 123.45
|
|
2136
|
+
*/
|
|
2137
|
+
function createAffixesFilterPreprocessor({ prefix, postfix, }) {
|
|
2138
|
+
return ({ elementState, data }) => {
|
|
2139
|
+
const { cleanValue: cleanData } = extractAffixes(data, {
|
|
2140
|
+
prefix,
|
|
2141
|
+
postfix,
|
|
2142
|
+
});
|
|
2143
|
+
return {
|
|
2144
|
+
elementState,
|
|
2145
|
+
data: cleanData,
|
|
2146
|
+
};
|
|
2147
|
+
};
|
|
2148
|
+
}
|
|
2149
|
+
|
|
2150
|
+
function generateMaskExpression({ decimalPseudoSeparators, decimalSeparator, maximumFractionDigits, min, minusSign, postfix, prefix, pseudoMinuses, thousandSeparator, }) {
|
|
2151
|
+
const computedPrefix = min < 0 && [minusSign, ...pseudoMinuses].includes(prefix)
|
|
2152
|
+
? ''
|
|
2153
|
+
: computeAllOptionalCharsRegExp(prefix);
|
|
2154
|
+
const digit = String.raw `\d`;
|
|
2155
|
+
const optionalMinus = min < 0 ? `[${minusSign}${pseudoMinuses.map((x) => `\\${x}`).join('')}]?` : '';
|
|
2156
|
+
const integerPart = thousandSeparator
|
|
2157
|
+
? `[${digit}${escapeRegExp(thousandSeparator).replaceAll(/\s/g, String.raw `\s`)}]*`
|
|
2158
|
+
: `[${digit}]*`;
|
|
2159
|
+
const precisionPart = Number.isFinite(maximumFractionDigits)
|
|
2160
|
+
? maximumFractionDigits
|
|
2161
|
+
: '';
|
|
2162
|
+
const decimalPart = maximumFractionDigits > 0
|
|
2163
|
+
? `([${escapeRegExp(decimalSeparator)}${decimalPseudoSeparators
|
|
2164
|
+
.map(escapeRegExp)
|
|
2165
|
+
.join('')}]${digit}{0,${precisionPart}})?`
|
|
2166
|
+
: '';
|
|
2167
|
+
const computedPostfix = computeAllOptionalCharsRegExp(postfix);
|
|
2168
|
+
return new RegExp(`^${computedPrefix}${optionalMinus}${integerPart}${decimalPart}${computedPostfix}$`);
|
|
2169
|
+
}
|
|
2170
|
+
function computeAllOptionalCharsRegExp(str) {
|
|
2171
|
+
return str
|
|
2172
|
+
? `${str
|
|
2173
|
+
.split('')
|
|
2174
|
+
.map((char) => `${escapeRegExp(char)}?`)
|
|
2175
|
+
.join('')}`
|
|
2176
|
+
: '';
|
|
2177
|
+
}
|
|
2178
|
+
|
|
2179
|
+
function maskitoParseNumber(maskedNumber,
|
|
2180
|
+
// TODO(v4): decimalSeparatorOrParams: MaskitoNumberParams | string => params: MaskitoNumberParams = {}
|
|
2181
|
+
decimalSeparatorOrParams = {}) {
|
|
2182
|
+
const { decimalSeparator = '.', minusSign = '' } = typeof decimalSeparatorOrParams === 'string'
|
|
2183
|
+
? { decimalSeparator: decimalSeparatorOrParams }
|
|
2184
|
+
: decimalSeparatorOrParams;
|
|
2185
|
+
const hasNegativeSign = !!new RegExp(`^\\D*[${escapeRegExp(minusSign)}\\${DEFAULT_PSEUDO_MINUSES.join('\\')}]`).exec(maskedNumber);
|
|
2186
|
+
const escapedDecimalSeparator = escapeRegExp(decimalSeparator);
|
|
2187
|
+
const unmaskedNumber = maskedNumber
|
|
2188
|
+
// drop all decimal separators not followed by a digit
|
|
2189
|
+
.replaceAll(new RegExp(`${escapedDecimalSeparator}(?!\\d)`, 'g'), '')
|
|
2190
|
+
// drop all non-digit characters except decimal separator
|
|
2191
|
+
.replaceAll(new RegExp(`[^\\d${escapedDecimalSeparator}]`, 'g'), '')
|
|
2192
|
+
.replace(decimalSeparator, decimalSeparator && '.');
|
|
2193
|
+
if (unmaskedNumber) {
|
|
2194
|
+
const sign = hasNegativeSign ? CHAR_HYPHEN : '';
|
|
2195
|
+
return Number(`${sign}${unmaskedNumber}`);
|
|
2196
|
+
}
|
|
2197
|
+
return NaN;
|
|
2198
|
+
}
|
|
2199
|
+
|
|
2200
|
+
function maskitoStringifyNumber(number, params) {
|
|
2201
|
+
if (Number.isNaN(number) || number === null) {
|
|
2202
|
+
return '';
|
|
2203
|
+
}
|
|
2204
|
+
const { min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER, decimalSeparator = '.', } = params;
|
|
2205
|
+
const value = clamp(number, min, max).toString().replace('.', decimalSeparator);
|
|
2206
|
+
return maskitoTransform(value, maskitoNumberOptionsGenerator(params));
|
|
2207
|
+
}
|
|
2208
|
+
|
|
2209
|
+
/**
|
|
2210
|
+
* Convert number to string with replacing exponent part on decimals
|
|
2211
|
+
*
|
|
2212
|
+
* @param value the number
|
|
2213
|
+
* @return string representation of a number
|
|
2214
|
+
*/
|
|
2215
|
+
function stringifyNumberWithoutExp(value) {
|
|
2216
|
+
var _a;
|
|
2217
|
+
const valueAsString = String(value);
|
|
2218
|
+
const [numberPart = '', expPart] = valueAsString.split('e-');
|
|
2219
|
+
let valueWithoutExp = valueAsString;
|
|
2220
|
+
if (expPart) {
|
|
2221
|
+
const [, fractionalPart] = numberPart.split('.');
|
|
2222
|
+
const decimalDigits = Number(expPart) + ((_a = fractionalPart === null || fractionalPart === void 0 ? void 0 : fractionalPart.length) !== null && _a !== void 0 ? _a : 0);
|
|
2223
|
+
valueWithoutExp = value.toFixed(decimalDigits);
|
|
2224
|
+
}
|
|
2225
|
+
return valueWithoutExp;
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2228
|
+
function toNumberParts(value, { decimalSeparator, minusSign }) {
|
|
2229
|
+
const [integerWithMinus = '', decimalPart = ''] = decimalSeparator
|
|
2230
|
+
? value.split(decimalSeparator)
|
|
2231
|
+
: [value];
|
|
2232
|
+
const escapedMinus = escapeRegExp(minusSign);
|
|
2233
|
+
const [, minus = '', integerPart = ''] = new RegExp(`^(?:[^\\d${escapedMinus}])?(${escapedMinus})?(.*)`).exec(integerWithMinus) || [];
|
|
2234
|
+
return { minus, integerPart, decimalPart };
|
|
2235
|
+
}
|
|
2236
|
+
|
|
2237
|
+
function validateDecimalPseudoSeparators({ decimalSeparator, thousandSeparator, decimalPseudoSeparators = DEFAULT_DECIMAL_PSEUDO_SEPARATORS, }) {
|
|
2238
|
+
return decimalPseudoSeparators.filter((char) => char !== thousandSeparator && char !== decimalSeparator);
|
|
2239
|
+
}
|
|
2240
|
+
|
|
2241
|
+
/**
|
|
2242
|
+
* If `minimumFractionDigits` is `>0`, it pads decimal part with zeroes
|
|
2243
|
+
* (until number of digits after decimalSeparator is equal to the `minimumFractionDigits`).
|
|
2244
|
+
* @example 1,42 => (`minimumFractionDigits` is equal to 4) => 1,4200.
|
|
2245
|
+
*/
|
|
2246
|
+
function createDecimalZeroPaddingPostprocessor({ decimalSeparator, minimumFractionDigits, prefix, postfix, minusSign, }) {
|
|
2247
|
+
if (!minimumFractionDigits) {
|
|
2248
|
+
return identity;
|
|
2249
|
+
}
|
|
2250
|
+
return ({ value, selection }) => {
|
|
2251
|
+
const { cleanValue, extractedPrefix, extractedPostfix } = extractAffixes(value, {
|
|
2252
|
+
prefix,
|
|
2253
|
+
postfix,
|
|
2254
|
+
});
|
|
2255
|
+
if (Number.isNaN(maskitoParseNumber(cleanValue, { decimalSeparator, minusSign }))) {
|
|
2256
|
+
return { value, selection };
|
|
2257
|
+
}
|
|
2258
|
+
const [integerPart, decimalPart = ''] = cleanValue.split(decimalSeparator);
|
|
2259
|
+
return {
|
|
2260
|
+
value: extractedPrefix +
|
|
2261
|
+
integerPart +
|
|
2262
|
+
decimalSeparator +
|
|
2263
|
+
decimalPart.padEnd(minimumFractionDigits, '0') +
|
|
2264
|
+
extractedPostfix,
|
|
2265
|
+
selection,
|
|
2266
|
+
};
|
|
2267
|
+
};
|
|
2268
|
+
}
|
|
2269
|
+
|
|
2270
|
+
/**
|
|
2271
|
+
* Make textfield empty if there is no integer part and all decimal digits are zeroes.
|
|
2272
|
+
* @example 0|,00 => Backspace => Empty.
|
|
2273
|
+
* @example -0|,00 => Backspace => -.
|
|
2274
|
+
* @example ,42| => Backspace x2 => ,|00 => Backspace => Empty
|
|
2275
|
+
*/
|
|
2276
|
+
function emptyPostprocessor({ prefix, postfix, decimalSeparator, minusSign, }) {
|
|
2277
|
+
return ({ value, selection }) => {
|
|
2278
|
+
const [caretIndex] = selection;
|
|
2279
|
+
const { cleanValue, extractedPrefix, extractedPostfix } = extractAffixes(value, {
|
|
2280
|
+
prefix,
|
|
2281
|
+
postfix,
|
|
2282
|
+
});
|
|
2283
|
+
const { minus, integerPart, decimalPart } = toNumberParts(cleanValue, {
|
|
2284
|
+
decimalSeparator,
|
|
2285
|
+
minusSign,
|
|
2286
|
+
});
|
|
2287
|
+
const aloneDecimalSeparator = !integerPart &&
|
|
2288
|
+
!decimalPart &&
|
|
2289
|
+
Boolean(decimalSeparator) &&
|
|
2290
|
+
cleanValue.includes(decimalSeparator);
|
|
2291
|
+
if ((!integerPart &&
|
|
2292
|
+
!Number(decimalPart) &&
|
|
2293
|
+
caretIndex === (minus + extractedPrefix).length) ||
|
|
2294
|
+
aloneDecimalSeparator) {
|
|
2295
|
+
return {
|
|
2296
|
+
selection,
|
|
2297
|
+
value: extractedPrefix + minus + extractedPostfix,
|
|
2298
|
+
};
|
|
2299
|
+
}
|
|
2300
|
+
return { value, selection };
|
|
2301
|
+
};
|
|
2302
|
+
}
|
|
2303
|
+
|
|
2304
|
+
/**
|
|
2305
|
+
* This preprocessor works only once at initialization phase (when `new Maskito(...)` is executed).
|
|
2306
|
+
* This preprocessor helps to avoid conflicts during transition from one mask to another (for the same input).
|
|
2307
|
+
* For example, the developer changes postfix (or other mask's props) during run-time.
|
|
2308
|
+
* ```
|
|
2309
|
+
* let maskitoOptions = maskitoNumberOptionsGenerator({postfix: ' year'});
|
|
2310
|
+
* // [3 seconds later]
|
|
2311
|
+
* maskitoOptions = maskitoNumberOptionsGenerator({postfix: ' years'});
|
|
2312
|
+
* ```
|
|
2313
|
+
*/
|
|
2314
|
+
function createInitializationOnlyPreprocessor({ decimalPseudoSeparators, decimalSeparator, minusSign, postfix, prefix, pseudoMinuses, }) {
|
|
2315
|
+
let isInitializationPhase = true;
|
|
2316
|
+
const cleanNumberMask = generateMaskExpression({
|
|
2317
|
+
decimalSeparator,
|
|
2318
|
+
decimalPseudoSeparators,
|
|
2319
|
+
pseudoMinuses,
|
|
2320
|
+
prefix: '',
|
|
2321
|
+
postfix: '',
|
|
2322
|
+
thousandSeparator: '',
|
|
2323
|
+
maximumFractionDigits: Infinity,
|
|
2324
|
+
min: Number.MIN_SAFE_INTEGER,
|
|
2325
|
+
minusSign,
|
|
2326
|
+
});
|
|
2327
|
+
return ({ elementState, data }) => {
|
|
2328
|
+
if (!isInitializationPhase) {
|
|
2329
|
+
return { elementState, data };
|
|
2330
|
+
}
|
|
2331
|
+
isInitializationPhase = false;
|
|
2332
|
+
const { value, selection } = elementState;
|
|
2333
|
+
const [from, to] = selection;
|
|
2334
|
+
const { extractedPrefix, cleanValue, extractedPostfix } = extractAffixes(value, {
|
|
2335
|
+
prefix,
|
|
2336
|
+
postfix,
|
|
2337
|
+
});
|
|
2338
|
+
const cleanState = maskitoTransform({
|
|
2339
|
+
selection: [
|
|
2340
|
+
Math.max(from - extractedPrefix.length, 0),
|
|
2341
|
+
clamp(to - extractedPrefix.length, 0, cleanValue.length),
|
|
2342
|
+
],
|
|
2343
|
+
value: cleanValue,
|
|
2344
|
+
}, {
|
|
2345
|
+
mask: cleanNumberMask,
|
|
2346
|
+
});
|
|
2347
|
+
const [cleanFrom, cleanTo] = cleanState.selection;
|
|
2348
|
+
return {
|
|
2349
|
+
elementState: {
|
|
2350
|
+
selection: [
|
|
2351
|
+
cleanFrom + extractedPrefix.length,
|
|
2352
|
+
cleanTo + extractedPrefix.length,
|
|
2353
|
+
],
|
|
2354
|
+
value: extractedPrefix + cleanState.value + extractedPostfix,
|
|
2355
|
+
},
|
|
2356
|
+
data,
|
|
2357
|
+
};
|
|
2358
|
+
};
|
|
2359
|
+
}
|
|
2360
|
+
|
|
2361
|
+
/**
|
|
2362
|
+
* It removes repeated leading zeroes for integer part.
|
|
2363
|
+
* @example 0,|00005 => Backspace => |5
|
|
2364
|
+
* @example -0,|00005 => Backspace => -|5
|
|
2365
|
+
* @example User types "000000" => 0|
|
|
2366
|
+
* @example 0| => User types "5" => 5|
|
|
2367
|
+
*/
|
|
2368
|
+
function createLeadingZeroesValidationPostprocessor({ decimalSeparator, thousandSeparator, prefix, postfix, }) {
|
|
2369
|
+
const trimLeadingZeroes = (value) => {
|
|
2370
|
+
const escapedThousandSeparator = escapeRegExp(thousandSeparator);
|
|
2371
|
+
return value
|
|
2372
|
+
.replace(
|
|
2373
|
+
// all leading zeroes followed by another zero
|
|
2374
|
+
new RegExp(`^(\\D+)?[0${escapedThousandSeparator}]+(?=0)`), '$1')
|
|
2375
|
+
.replace(
|
|
2376
|
+
// zero followed by not-zero digit
|
|
2377
|
+
new RegExp(`^(\\D+)?[0${escapedThousandSeparator}]+(?=[1-9])`), '$1');
|
|
2378
|
+
};
|
|
2379
|
+
const countTrimmedZeroesBefore = (value, index) => {
|
|
2380
|
+
const valueBefore = value.slice(0, index);
|
|
2381
|
+
const followedByZero = value.slice(index).startsWith('0');
|
|
2382
|
+
return (valueBefore.length -
|
|
2383
|
+
trimLeadingZeroes(valueBefore).length +
|
|
2384
|
+
(followedByZero ? 1 : 0));
|
|
2385
|
+
};
|
|
2386
|
+
return ({ value, selection }) => {
|
|
2387
|
+
const [from, to] = selection;
|
|
2388
|
+
const { cleanValue, extractedPrefix, extractedPostfix } = extractAffixes(value, {
|
|
2389
|
+
prefix,
|
|
2390
|
+
postfix,
|
|
2391
|
+
});
|
|
2392
|
+
const hasDecimalSeparator = Boolean(decimalSeparator) && cleanValue.includes(decimalSeparator);
|
|
2393
|
+
const [integerPart = '', decimalPart = ''] = decimalSeparator
|
|
2394
|
+
? cleanValue.split(decimalSeparator)
|
|
2395
|
+
: [cleanValue];
|
|
2396
|
+
const zeroTrimmedIntegerPart = trimLeadingZeroes(integerPart);
|
|
2397
|
+
if (integerPart === zeroTrimmedIntegerPart) {
|
|
2398
|
+
return { value, selection };
|
|
2399
|
+
}
|
|
2400
|
+
const newFrom = from - countTrimmedZeroesBefore(value, from);
|
|
2401
|
+
const newTo = to - countTrimmedZeroesBefore(value, to);
|
|
2402
|
+
return {
|
|
2403
|
+
value: extractedPrefix +
|
|
2404
|
+
zeroTrimmedIntegerPart +
|
|
2405
|
+
(hasDecimalSeparator ? decimalSeparator : '') +
|
|
2406
|
+
decimalPart +
|
|
2407
|
+
extractedPostfix,
|
|
2408
|
+
selection: [Math.max(newFrom, 0), Math.max(newTo, 0)],
|
|
2409
|
+
};
|
|
2410
|
+
};
|
|
2411
|
+
}
|
|
2412
|
+
|
|
2413
|
+
/**
|
|
2414
|
+
* This postprocessor is connected with {@link createMinMaxPlugin}:
|
|
2415
|
+
* both validate `min`/`max` bounds of entered value (but at the different point of time).
|
|
2416
|
+
*/
|
|
2417
|
+
function createMinMaxPostprocessor({ min, max, decimalSeparator, minusSign, }) {
|
|
2418
|
+
return ({ value, selection }) => {
|
|
2419
|
+
const parsedNumber = maskitoParseNumber(value, { decimalSeparator, minusSign });
|
|
2420
|
+
const limitedValue =
|
|
2421
|
+
/**
|
|
2422
|
+
* We cannot limit lower bound if user enters positive number.
|
|
2423
|
+
* The same for upper bound and negative number.
|
|
2424
|
+
* ___
|
|
2425
|
+
* @example (min = 5)
|
|
2426
|
+
* Empty input => Without this condition user cannot type 42 (the first digit will be rejected)
|
|
2427
|
+
* ___
|
|
2428
|
+
* @example (max = -10)
|
|
2429
|
+
* Value is -10 => Without this condition user cannot delete 0 to enter another digit
|
|
2430
|
+
*/
|
|
2431
|
+
parsedNumber > 0 ? Math.min(parsedNumber, max) : Math.max(parsedNumber, min);
|
|
2432
|
+
if (parsedNumber && limitedValue !== parsedNumber) {
|
|
2433
|
+
const newValue = `${limitedValue}`
|
|
2434
|
+
.replace('.', decimalSeparator)
|
|
2435
|
+
.replace(CHAR_HYPHEN, minusSign);
|
|
2436
|
+
return {
|
|
2437
|
+
value: newValue,
|
|
2438
|
+
selection: [newValue.length, newValue.length],
|
|
2439
|
+
};
|
|
2440
|
+
}
|
|
2441
|
+
return {
|
|
2442
|
+
value,
|
|
2443
|
+
selection,
|
|
2444
|
+
};
|
|
2445
|
+
};
|
|
2446
|
+
}
|
|
2447
|
+
|
|
2448
|
+
/**
|
|
2449
|
+
* Manage caret-navigation when user "deletes" non-removable digits or separators
|
|
2450
|
+
* @example 1,|42 => Backspace => 1|,42 (only if `minimumFractionDigits` is `>0`)
|
|
2451
|
+
* @example 1|,42 => Delete => 1,|42 (only if `minimumFractionDigits` is `>0`)
|
|
2452
|
+
* @example 0,|00 => Delete => 0,0|0 (only if `minimumFractionDigits` is `>0`)
|
|
2453
|
+
* @example 1 |000 => Backspace => 1| 000 (always)
|
|
2454
|
+
*/
|
|
2455
|
+
function createNonRemovableCharsDeletionPreprocessor({ decimalSeparator, thousandSeparator, minimumFractionDigits, }) {
|
|
2456
|
+
return ({ elementState, data }, actionType) => {
|
|
2457
|
+
const { value, selection } = elementState;
|
|
2458
|
+
const [from, to] = selection;
|
|
2459
|
+
const selectedCharacters = value.slice(from, to);
|
|
2460
|
+
const nonRemovableSeparators = minimumFractionDigits
|
|
2461
|
+
? [decimalSeparator, thousandSeparator]
|
|
2462
|
+
: [thousandSeparator];
|
|
2463
|
+
const areNonRemovableZeroesSelected = Boolean(minimumFractionDigits) &&
|
|
2464
|
+
from > value.indexOf(decimalSeparator) &&
|
|
2465
|
+
Boolean(selectedCharacters.match(/^0+$/gi));
|
|
2466
|
+
if ((actionType !== 'deleteBackward' && actionType !== 'deleteForward') ||
|
|
2467
|
+
(!nonRemovableSeparators.includes(selectedCharacters) &&
|
|
2468
|
+
!areNonRemovableZeroesSelected)) {
|
|
2469
|
+
return {
|
|
2470
|
+
elementState,
|
|
2471
|
+
data,
|
|
2472
|
+
};
|
|
2473
|
+
}
|
|
2474
|
+
return {
|
|
2475
|
+
elementState: {
|
|
2476
|
+
value,
|
|
2477
|
+
selection: actionType === 'deleteForward' ? [to, to] : [from, from],
|
|
2478
|
+
},
|
|
2479
|
+
data,
|
|
2480
|
+
};
|
|
2481
|
+
};
|
|
2482
|
+
}
|
|
2483
|
+
|
|
2484
|
+
/**
|
|
2485
|
+
* It pads integer part with zero if user types decimal separator (for empty input).
|
|
2486
|
+
* @example Empty input => User types "," (decimal separator) => 0,|
|
|
2487
|
+
*/
|
|
2488
|
+
function createNotEmptyIntegerPartPreprocessor({ decimalSeparator, maximumFractionDigits, prefix, postfix, }) {
|
|
2489
|
+
const startWithDecimalSepRegExp = new RegExp(`^\\D*${escapeRegExp(decimalSeparator)}`);
|
|
2490
|
+
return ({ elementState, data }) => {
|
|
2491
|
+
const { value, selection } = elementState;
|
|
2492
|
+
const { cleanValue, extractedPrefix } = extractAffixes(value, {
|
|
2493
|
+
prefix,
|
|
2494
|
+
postfix,
|
|
2495
|
+
});
|
|
2496
|
+
const [from, to] = selection;
|
|
2497
|
+
const cleanFrom = clamp(from - extractedPrefix.length, 0, cleanValue.length);
|
|
2498
|
+
const cleanTo = clamp(to - extractedPrefix.length, 0, cleanValue.length);
|
|
2499
|
+
if (maximumFractionDigits <= 0 ||
|
|
2500
|
+
cleanValue.slice(0, cleanFrom).includes(decimalSeparator) ||
|
|
2501
|
+
cleanValue.slice(cleanTo).includes(decimalSeparator) ||
|
|
2502
|
+
!data.match(startWithDecimalSepRegExp)) {
|
|
2503
|
+
return { elementState, data };
|
|
2504
|
+
}
|
|
2505
|
+
const digitsBeforeCursor = /\d+/.exec(cleanValue.slice(0, cleanFrom));
|
|
2506
|
+
return {
|
|
2507
|
+
elementState,
|
|
2508
|
+
data: digitsBeforeCursor ? data : `0${data}`,
|
|
2509
|
+
};
|
|
2510
|
+
};
|
|
2511
|
+
}
|
|
2512
|
+
|
|
2513
|
+
/**
|
|
2514
|
+
* It replaces pseudo characters with valid one.
|
|
2515
|
+
* @example User types '.' (but separator is equal to comma) => dot is replaced with comma.
|
|
2516
|
+
* @example User types hyphen / en-dash / em-dash => it is replaced with minus.
|
|
2517
|
+
*/
|
|
2518
|
+
function createPseudoCharactersPreprocessor({ validCharacter, pseudoCharacters, prefix, postfix, }) {
|
|
2519
|
+
const pseudoCharactersRegExp = new RegExp(`[${pseudoCharacters.join('')}]`, 'gi');
|
|
2520
|
+
return ({ elementState, data }) => {
|
|
2521
|
+
const { value, selection } = elementState;
|
|
2522
|
+
const { cleanValue, extractedPostfix, extractedPrefix } = extractAffixes(value, {
|
|
2523
|
+
prefix,
|
|
2524
|
+
postfix,
|
|
2525
|
+
});
|
|
2526
|
+
return {
|
|
2527
|
+
elementState: {
|
|
2528
|
+
selection,
|
|
2529
|
+
value: extractedPrefix +
|
|
2530
|
+
cleanValue.replace(pseudoCharactersRegExp, validCharacter) +
|
|
2531
|
+
extractedPostfix,
|
|
2532
|
+
},
|
|
2533
|
+
data: data.replace(pseudoCharactersRegExp, validCharacter),
|
|
2534
|
+
};
|
|
2535
|
+
};
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2538
|
+
/**
|
|
2539
|
+
* It rejects new typed decimal separator if it already exists in text field.
|
|
2540
|
+
* Behaviour is similar to native <input type="number"> (Chrome).
|
|
2541
|
+
* @example 1|23,45 => Press comma (decimal separator) => 1|23,45 (do nothing).
|
|
2542
|
+
*/
|
|
2543
|
+
function createRepeatedDecimalSeparatorPreprocessor({ decimalSeparator, prefix, postfix, }) {
|
|
2544
|
+
if (!decimalSeparator) {
|
|
2545
|
+
return identity;
|
|
2546
|
+
}
|
|
2547
|
+
return ({ elementState, data }) => {
|
|
2548
|
+
const { value, selection } = elementState;
|
|
2549
|
+
const [from, to] = selection;
|
|
2550
|
+
const { cleanValue } = extractAffixes(value, { prefix, postfix });
|
|
2551
|
+
return {
|
|
2552
|
+
elementState,
|
|
2553
|
+
data: !cleanValue.includes(decimalSeparator) ||
|
|
2554
|
+
value.slice(from, to + 1).includes(decimalSeparator)
|
|
2555
|
+
? data
|
|
2556
|
+
: data.replaceAll(new RegExp(escapeRegExp(decimalSeparator), 'gi'), ''),
|
|
2557
|
+
};
|
|
2558
|
+
};
|
|
2559
|
+
}
|
|
2560
|
+
|
|
2561
|
+
/**
|
|
2562
|
+
* It adds symbol for separating thousands.
|
|
2563
|
+
* @example 1000000 => (thousandSeparator is equal to space) => 1 000 000.
|
|
2564
|
+
*/
|
|
2565
|
+
function createThousandSeparatorPostprocessor({ thousandSeparator, decimalSeparator, prefix, postfix, minusSign, }) {
|
|
2566
|
+
if (!thousandSeparator) {
|
|
2567
|
+
return identity;
|
|
2568
|
+
}
|
|
2569
|
+
const isAllSpaces = (...chars) => chars.every((x) => /\s/.test(x));
|
|
2570
|
+
return ({ value, selection }) => {
|
|
2571
|
+
const [initialFrom, initialTo] = selection;
|
|
2572
|
+
let [from, to] = selection;
|
|
2573
|
+
const { cleanValue, extractedPostfix, extractedPrefix } = extractAffixes(value, {
|
|
2574
|
+
prefix,
|
|
2575
|
+
postfix,
|
|
2576
|
+
});
|
|
2577
|
+
const { minus, integerPart, decimalPart } = toNumberParts(cleanValue, {
|
|
2578
|
+
decimalSeparator,
|
|
2579
|
+
minusSign,
|
|
2580
|
+
});
|
|
2581
|
+
const hasDecimalSeparator = decimalSeparator && cleanValue.includes(decimalSeparator);
|
|
2582
|
+
const deletedChars = cleanValue.length -
|
|
2583
|
+
(minus +
|
|
2584
|
+
integerPart +
|
|
2585
|
+
(hasDecimalSeparator ? decimalSeparator + decimalPart : '')).length;
|
|
2586
|
+
if (deletedChars > 0 && initialFrom && initialFrom <= deletedChars) {
|
|
2587
|
+
from -= deletedChars;
|
|
2588
|
+
}
|
|
2589
|
+
if (deletedChars > 0 && initialTo && initialTo <= deletedChars) {
|
|
2590
|
+
to -= deletedChars;
|
|
2591
|
+
}
|
|
2592
|
+
const processedIntegerPart = Array.from(integerPart).reduceRight((formattedValuePart, char, i) => {
|
|
2593
|
+
const isLeadingThousandSeparator = !i && char === thousandSeparator;
|
|
2594
|
+
const isPositionForSeparator = !isLeadingThousandSeparator &&
|
|
2595
|
+
Boolean(formattedValuePart.length) &&
|
|
2596
|
+
(formattedValuePart.length + 1) % 4 === 0;
|
|
2597
|
+
const isSeparator = char === thousandSeparator || isAllSpaces(char, thousandSeparator);
|
|
2598
|
+
if (isPositionForSeparator && isSeparator) {
|
|
2599
|
+
return thousandSeparator + formattedValuePart;
|
|
2600
|
+
}
|
|
2601
|
+
if (!isPositionForSeparator && isSeparator) {
|
|
2602
|
+
if (i && i <= initialFrom) {
|
|
2603
|
+
from--;
|
|
2604
|
+
}
|
|
2605
|
+
if (i && i <= initialTo) {
|
|
2606
|
+
to--;
|
|
2607
|
+
}
|
|
2608
|
+
return formattedValuePart;
|
|
2609
|
+
}
|
|
2610
|
+
if (!isPositionForSeparator) {
|
|
2611
|
+
return char + formattedValuePart;
|
|
2612
|
+
}
|
|
2613
|
+
if (i < initialFrom) {
|
|
2614
|
+
from++;
|
|
2615
|
+
}
|
|
2616
|
+
if (i < initialTo) {
|
|
2617
|
+
to++;
|
|
2618
|
+
}
|
|
2619
|
+
return char + thousandSeparator + formattedValuePart;
|
|
2620
|
+
}, '');
|
|
2621
|
+
return {
|
|
2622
|
+
value: extractedPrefix +
|
|
2623
|
+
minus +
|
|
2624
|
+
processedIntegerPart +
|
|
2625
|
+
(hasDecimalSeparator ? decimalSeparator : '') +
|
|
2626
|
+
decimalPart +
|
|
2627
|
+
extractedPostfix,
|
|
2628
|
+
selection: [from, to],
|
|
2629
|
+
};
|
|
2630
|
+
};
|
|
2631
|
+
}
|
|
2632
|
+
|
|
2633
|
+
/**
|
|
2634
|
+
* It drops decimal part if `maximumFractionDigits` is zero.
|
|
2635
|
+
* @example User pastes '123.45' (but `maximumFractionDigits` is zero) => 123
|
|
2636
|
+
*/
|
|
2637
|
+
function createZeroPrecisionPreprocessor({ maximumFractionDigits, decimalSeparator, prefix, postfix, }) {
|
|
2638
|
+
if (maximumFractionDigits > 0 ||
|
|
2639
|
+
!decimalSeparator // all separators should be treated only as thousand separators
|
|
2640
|
+
) {
|
|
2641
|
+
return identity;
|
|
2642
|
+
}
|
|
2643
|
+
const decimalPartRegExp = new RegExp(`${escapeRegExp(decimalSeparator)}.*$`, 'g');
|
|
2644
|
+
return ({ elementState, data }) => {
|
|
2645
|
+
const { value, selection } = elementState;
|
|
2646
|
+
const { cleanValue, extractedPrefix, extractedPostfix } = extractAffixes(value, {
|
|
2647
|
+
prefix,
|
|
2648
|
+
postfix,
|
|
2649
|
+
});
|
|
2650
|
+
const [from, to] = selection;
|
|
2651
|
+
const newValue = extractedPrefix +
|
|
2652
|
+
cleanValue.replace(decimalPartRegExp, '') +
|
|
2653
|
+
extractedPostfix;
|
|
2654
|
+
return {
|
|
2655
|
+
elementState: {
|
|
2656
|
+
selection: [
|
|
2657
|
+
Math.min(from, newValue.length),
|
|
2658
|
+
Math.min(to, newValue.length),
|
|
2659
|
+
],
|
|
2660
|
+
value: newValue,
|
|
2661
|
+
},
|
|
2662
|
+
data: data.replace(decimalPartRegExp, ''),
|
|
2663
|
+
};
|
|
2664
|
+
};
|
|
2665
|
+
}
|
|
2666
|
+
|
|
2667
|
+
const DUMMY_SELECTION = [0, 0];
|
|
2668
|
+
/**
|
|
2669
|
+
* It removes repeated leading zeroes for integer part on blur-event.
|
|
2670
|
+
* @example 000000 => blur => 0
|
|
2671
|
+
* @example 00005 => blur => 5
|
|
2672
|
+
*/
|
|
2673
|
+
function createLeadingZeroesValidationPlugin({ decimalSeparator, thousandSeparator, prefix, postfix, }) {
|
|
2674
|
+
const dropRepeatedLeadingZeroes = createLeadingZeroesValidationPostprocessor({
|
|
2675
|
+
decimalSeparator,
|
|
2676
|
+
thousandSeparator,
|
|
2677
|
+
prefix,
|
|
2678
|
+
postfix,
|
|
2679
|
+
});
|
|
2680
|
+
return maskitoEventHandler('blur', (element) => {
|
|
2681
|
+
const newValue = dropRepeatedLeadingZeroes({
|
|
2682
|
+
value: element.value,
|
|
2683
|
+
selection: DUMMY_SELECTION,
|
|
2684
|
+
}, { value: '', selection: DUMMY_SELECTION }).value;
|
|
2685
|
+
maskitoUpdateElement(element, newValue);
|
|
2686
|
+
}, { capture: true });
|
|
2687
|
+
}
|
|
2688
|
+
|
|
2689
|
+
/**
|
|
2690
|
+
* This plugin is connected with {@link createMinMaxPostprocessor}:
|
|
2691
|
+
* both validate `min`/`max` bounds of entered value (but at the different point of time).
|
|
2692
|
+
*/
|
|
2693
|
+
function createMinMaxPlugin({ min, max, decimalSeparator, minusSign, }) {
|
|
2694
|
+
return maskitoEventHandler('blur', (element, options) => {
|
|
2695
|
+
const parsedNumber = maskitoParseNumber(element.value, {
|
|
2696
|
+
decimalSeparator,
|
|
2697
|
+
minusSign,
|
|
2698
|
+
});
|
|
2699
|
+
const clampedNumber = clamp(parsedNumber, min, max);
|
|
2700
|
+
if (!Number.isNaN(parsedNumber) && parsedNumber !== clampedNumber) {
|
|
2701
|
+
maskitoUpdateElement(element, maskitoTransform(stringifyNumberWithoutExp(clampedNumber), options));
|
|
2702
|
+
}
|
|
2703
|
+
}, { capture: true });
|
|
2704
|
+
}
|
|
2705
|
+
|
|
2706
|
+
/**
|
|
2707
|
+
* It pads EMPTY integer part with zero if decimal parts exists.
|
|
2708
|
+
* It works on blur event only!
|
|
2709
|
+
* @example 1|,23 => Backspace => Blur => 0,23
|
|
2710
|
+
*/
|
|
2711
|
+
function createNotEmptyIntegerPlugin({ decimalSeparator, prefix, postfix, }) {
|
|
2712
|
+
if (!decimalSeparator) {
|
|
2713
|
+
return noop;
|
|
2714
|
+
}
|
|
2715
|
+
return maskitoEventHandler('blur', (element) => {
|
|
2716
|
+
const { cleanValue, extractedPostfix, extractedPrefix } = extractAffixes(element.value, { prefix, postfix });
|
|
2717
|
+
const newValue = extractedPrefix +
|
|
2718
|
+
cleanValue.replace(new RegExp(`^(\\D+)?${escapeRegExp(decimalSeparator)}`), `$10${decimalSeparator}`) +
|
|
2719
|
+
extractedPostfix;
|
|
2720
|
+
maskitoUpdateElement(element, newValue);
|
|
2721
|
+
}, { capture: true });
|
|
2722
|
+
}
|
|
2723
|
+
|
|
2724
|
+
const DEFAULT_PSEUDO_MINUSES = [
|
|
2725
|
+
CHAR_HYPHEN,
|
|
2726
|
+
CHAR_EN_DASH,
|
|
2727
|
+
CHAR_EM_DASH,
|
|
2728
|
+
CHAR_JP_HYPHEN,
|
|
2729
|
+
CHAR_MINUS,
|
|
2730
|
+
];
|
|
2731
|
+
function maskitoNumberOptionsGenerator({ max = Number.MAX_SAFE_INTEGER, min = Number.MIN_SAFE_INTEGER, precision = 0, thousandSeparator = CHAR_NO_BREAK_SPACE, decimalSeparator = '.', decimalPseudoSeparators, decimalZeroPadding = false, prefix: unsafePrefix = '', postfix = '', minusSign = CHAR_MINUS, maximumFractionDigits = precision, minimumFractionDigits = decimalZeroPadding ? maximumFractionDigits : 0, } = {}) {
|
|
2732
|
+
const pseudoMinuses = DEFAULT_PSEUDO_MINUSES.filter((char) => char !== thousandSeparator && char !== decimalSeparator && char !== minusSign);
|
|
2733
|
+
const validatedDecimalPseudoSeparators = validateDecimalPseudoSeparators({
|
|
2734
|
+
decimalSeparator,
|
|
2735
|
+
thousandSeparator,
|
|
2736
|
+
decimalPseudoSeparators,
|
|
2737
|
+
});
|
|
2738
|
+
const prefix = unsafePrefix.endsWith(decimalSeparator) && maximumFractionDigits > 0
|
|
2739
|
+
? `${unsafePrefix}${CHAR_ZERO_WIDTH_SPACE}`
|
|
2740
|
+
: unsafePrefix;
|
|
2741
|
+
const initializationOnlyPreprocessor = createInitializationOnlyPreprocessor({
|
|
2742
|
+
decimalSeparator,
|
|
2743
|
+
decimalPseudoSeparators: validatedDecimalPseudoSeparators,
|
|
2744
|
+
pseudoMinuses,
|
|
2745
|
+
prefix,
|
|
2746
|
+
postfix,
|
|
2747
|
+
minusSign,
|
|
2748
|
+
});
|
|
2749
|
+
decimalSeparator =
|
|
2750
|
+
maximumFractionDigits <= 0 && decimalSeparator === thousandSeparator
|
|
2751
|
+
? ''
|
|
2752
|
+
: decimalSeparator;
|
|
2753
|
+
return Object.assign(Object.assign({}, MASKITO_DEFAULT_OPTIONS), { mask: generateMaskExpression({
|
|
2754
|
+
decimalSeparator,
|
|
2755
|
+
maximumFractionDigits,
|
|
2756
|
+
min,
|
|
2757
|
+
minusSign,
|
|
2758
|
+
postfix,
|
|
2759
|
+
prefix,
|
|
2760
|
+
pseudoMinuses,
|
|
2761
|
+
thousandSeparator,
|
|
2762
|
+
decimalPseudoSeparators: validatedDecimalPseudoSeparators,
|
|
2763
|
+
}), preprocessors: [
|
|
2764
|
+
createFullWidthToHalfWidthPreprocessor(),
|
|
2765
|
+
initializationOnlyPreprocessor,
|
|
2766
|
+
createAffixesFilterPreprocessor({ prefix, postfix }),
|
|
2767
|
+
createPseudoCharactersPreprocessor({
|
|
2768
|
+
validCharacter: minusSign,
|
|
2769
|
+
pseudoCharacters: pseudoMinuses,
|
|
2770
|
+
prefix,
|
|
2771
|
+
postfix,
|
|
2772
|
+
}),
|
|
2773
|
+
createPseudoCharactersPreprocessor({
|
|
2774
|
+
validCharacter: decimalSeparator,
|
|
2775
|
+
pseudoCharacters: validatedDecimalPseudoSeparators,
|
|
2776
|
+
prefix,
|
|
2777
|
+
postfix,
|
|
2778
|
+
}),
|
|
2779
|
+
createNotEmptyIntegerPartPreprocessor({
|
|
2780
|
+
decimalSeparator,
|
|
2781
|
+
maximumFractionDigits,
|
|
2782
|
+
prefix,
|
|
2783
|
+
postfix,
|
|
2784
|
+
}),
|
|
2785
|
+
createNonRemovableCharsDeletionPreprocessor({
|
|
2786
|
+
decimalSeparator,
|
|
2787
|
+
minimumFractionDigits,
|
|
2788
|
+
thousandSeparator,
|
|
2789
|
+
}),
|
|
2790
|
+
createZeroPrecisionPreprocessor({
|
|
2791
|
+
maximumFractionDigits,
|
|
2792
|
+
decimalSeparator,
|
|
2793
|
+
prefix,
|
|
2794
|
+
postfix,
|
|
2795
|
+
}),
|
|
2796
|
+
createRepeatedDecimalSeparatorPreprocessor({
|
|
2797
|
+
decimalSeparator,
|
|
2798
|
+
prefix,
|
|
2799
|
+
postfix,
|
|
2800
|
+
}),
|
|
2801
|
+
], postprocessors: [
|
|
2802
|
+
createMinMaxPostprocessor({ decimalSeparator, min, max, minusSign }),
|
|
2803
|
+
maskitoPrefixPostprocessorGenerator(prefix),
|
|
2804
|
+
maskitoPostfixPostprocessorGenerator(postfix),
|
|
2805
|
+
createThousandSeparatorPostprocessor({
|
|
2806
|
+
decimalSeparator,
|
|
2807
|
+
thousandSeparator,
|
|
2808
|
+
prefix,
|
|
2809
|
+
postfix,
|
|
2810
|
+
minusSign,
|
|
2811
|
+
}),
|
|
2812
|
+
createDecimalZeroPaddingPostprocessor({
|
|
2813
|
+
decimalSeparator,
|
|
2814
|
+
prefix,
|
|
2815
|
+
postfix,
|
|
2816
|
+
minusSign,
|
|
2817
|
+
minimumFractionDigits: Math.min(minimumFractionDigits, maximumFractionDigits),
|
|
2818
|
+
}),
|
|
2819
|
+
emptyPostprocessor({
|
|
2820
|
+
prefix,
|
|
2821
|
+
postfix,
|
|
2822
|
+
decimalSeparator,
|
|
2823
|
+
minusSign,
|
|
2824
|
+
}),
|
|
2825
|
+
], plugins: [
|
|
2826
|
+
createLeadingZeroesValidationPlugin({
|
|
2827
|
+
decimalSeparator,
|
|
2828
|
+
thousandSeparator,
|
|
2829
|
+
prefix,
|
|
2830
|
+
postfix,
|
|
2831
|
+
}),
|
|
2832
|
+
createNotEmptyIntegerPlugin({
|
|
2833
|
+
decimalSeparator,
|
|
2834
|
+
prefix,
|
|
2835
|
+
postfix,
|
|
2836
|
+
}),
|
|
2837
|
+
createMinMaxPlugin({ min, max, decimalSeparator, minusSign }),
|
|
2838
|
+
], overwriteMode: minimumFractionDigits > 0
|
|
2839
|
+
? ({ value, selection: [from] }) => from <= value.indexOf(decimalSeparator) ? 'shift' : 'replace'
|
|
2840
|
+
: 'shift' });
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2111
2843
|
/**
|
|
2112
2844
|
* React adds `_valueTracker` property to every textfield elements for its internal logic with controlled inputs.
|
|
2113
2845
|
* Also, React monkey-patches `value`-setter of the native textfield elements to update state inside its `_valueTracker`.
|
|
@@ -2221,15 +2953,5 @@ const useMaskito = ({
|
|
|
2221
2953
|
return onRefChange;
|
|
2222
2954
|
};
|
|
2223
2955
|
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
void 0
|
|
2227
|
-
);
|
|
2228
|
-
useEffect(() => {
|
|
2229
|
-
setPopoverSupported(supportsPopover());
|
|
2230
|
-
}, []);
|
|
2231
|
-
return popoverSupported;
|
|
2232
|
-
}
|
|
2233
|
-
|
|
2234
|
-
export { useMaskito as a, maskitoWithPlaceholder as b, maskitoParseDate as c, maskitoDateOptionsGenerator as d, maskitoTimeOptionsGenerator as e, maskitoDateRangeOptionsGenerator as m, usePopoverSupport as u };
|
|
2235
|
-
//# sourceMappingURL=usePopoverSupport-B9Lsqryr-DhZHMoNb.js.map
|
|
2956
|
+
export { maskitoWithPlaceholder as a, maskitoParseDate as b, maskitoDateOptionsGenerator as c, maskitoTimeOptionsGenerator as d, maskitoNumberOptionsGenerator as e, maskitoParseNumber as f, maskitoStringifyNumber as g, maskitoDateRangeOptionsGenerator as m, useMaskito as u };
|
|
2957
|
+
//# sourceMappingURL=index.esm-dyoPQhi6.js.map
|