UNPKG

122 kBJavaScriptView Raw
1import * as i0 from '@angular/core';
2import { InjectionToken, EventEmitter, inject, Injectable, ElementRef, Renderer2, makeEnvironmentProviders, Directive, Input, Output, HostListener, Pipe } from '@angular/core';
3import { DOCUMENT } from '@angular/common';
4import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
5
6const NGX_MASK_CONFIG = new InjectionToken('ngx-mask config');
7const NEW_CONFIG = new InjectionToken('new ngx-mask config');
8const INITIAL_CONFIG = new InjectionToken('initial ngx-mask config');
9const initialConfig = {
10 suffix: '',
11 prefix: '',
12 thousandSeparator: ' ',
13 decimalMarker: ['.', ','],
14 clearIfNotMatch: false,
15 showTemplate: false,
16 showMaskTyped: false,
17 placeHolderCharacter: '_',
18 dropSpecialCharacters: true,
19 hiddenInput: undefined,
20 shownMaskExpression: '',
21 separatorLimit: '',
22 allowNegativeNumbers: false,
23 validation: true,
24 specialCharacters: ['-', '/', '(', ')', '.', ':', ' ', '+', ',', '@', '[', ']', '"', "'"],
25 leadZeroDateTime: false,
26 apm: false,
27 leadZero: false,
28 keepCharacterPositions: false,
29 triggerOnMaskChange: false,
30 inputTransformFn: (value) => value,
31 outputTransformFn: (value) => value,
32 maskFilled: new EventEmitter(),
33 patterns: {
34 '0': {
35 pattern: new RegExp('\\d'),
36 },
37 '9': {
38 pattern: new RegExp('\\d'),
39 optional: true,
40 },
41 X: {
42 pattern: new RegExp('\\d'),
43 symbol: '*',
44 },
45 A: {
46 pattern: new RegExp('[a-zA-Z0-9]'),
47 },
48 S: {
49 pattern: new RegExp('[a-zA-Z]'),
50 },
51 U: {
52 pattern: new RegExp('[A-Z]'),
53 },
54 L: {
55 pattern: new RegExp('[a-z]'),
56 },
57 d: {
58 pattern: new RegExp('\\d'),
59 },
60 m: {
61 pattern: new RegExp('\\d'),
62 },
63 M: {
64 pattern: new RegExp('\\d'),
65 },
66 H: {
67 pattern: new RegExp('\\d'),
68 },
69 h: {
70 pattern: new RegExp('\\d'),
71 },
72 s: {
73 pattern: new RegExp('\\d'),
74 },
75 },
76};
77const timeMasks = [
78 "Hh:m0:s0" /* MaskExpression.HOURS_MINUTES_SECONDS */,
79 "Hh:m0" /* MaskExpression.HOURS_MINUTES */,
80 "m0:s0" /* MaskExpression.MINUTES_SECONDS */,
81];
82const withoutValidation = [
83 "percent" /* MaskExpression.PERCENT */,
84 "Hh" /* MaskExpression.HOURS_HOUR */,
85 "s0" /* MaskExpression.SECONDS */,
86 "m0" /* MaskExpression.MINUTES */,
87 "separator" /* MaskExpression.SEPARATOR */,
88 "d0/M0/0000" /* MaskExpression.DAYS_MONTHS_YEARS */,
89 "d0/M0" /* MaskExpression.DAYS_MONTHS */,
90 "d0" /* MaskExpression.DAYS */,
91 "M0" /* MaskExpression.MONTHS */,
92];
93
94class NgxMaskApplierService {
95 constructor() {
96 this._config = inject(NGX_MASK_CONFIG);
97 this.dropSpecialCharacters = this._config.dropSpecialCharacters;
98 this.hiddenInput = this._config.hiddenInput;
99 this.clearIfNotMatch = this._config.clearIfNotMatch;
100 this.specialCharacters = this._config.specialCharacters;
101 this.patterns = this._config.patterns;
102 this.prefix = this._config.prefix;
103 this.suffix = this._config.suffix;
104 this.thousandSeparator = this._config.thousandSeparator;
105 this.decimalMarker = this._config.decimalMarker;
106 this.showMaskTyped = this._config.showMaskTyped;
107 this.placeHolderCharacter = this._config.placeHolderCharacter;
108 this.validation = this._config.validation;
109 this.separatorLimit = this._config.separatorLimit;
110 this.allowNegativeNumbers = this._config.allowNegativeNumbers;
111 this.leadZeroDateTime = this._config.leadZeroDateTime;
112 this.leadZero = this._config.leadZero;
113 this.apm = this._config.apm;
114 this.inputTransformFn = this._config.inputTransformFn;
115 this.outputTransformFn = this._config.outputTransformFn;
116 this.keepCharacterPositions = this._config.keepCharacterPositions;
117 this._shift = new Set();
118 this.plusOnePosition = false;
119 this.maskExpression = '';
120 this.actualValue = '';
121 this.showKeepCharacterExp = '';
122 this.shownMaskExpression = '';
123 this.deletedSpecialCharacter = false;
124 this._formatWithSeparators = (str, thousandSeparatorChar, decimalChars, precision) => {
125 let x = [];
126 let decimalChar = '';
127 if (Array.isArray(decimalChars)) {
128 const regExp = new RegExp(decimalChars.map((v) => ('[\\^$.|?*+()'.indexOf(v) >= 0 ? `\\${v}` : v)).join('|'));
129 x = str.split(regExp);
130 decimalChar = str.match(regExp)?.[0] ?? "" /* MaskExpression.EMPTY_STRING */;
131 }
132 else {
133 x = str.split(decimalChars);
134 decimalChar = decimalChars;
135 }
136 const decimals = x.length > 1 ? `${decimalChar}${x[1]}` : "" /* MaskExpression.EMPTY_STRING */;
137 let res = x[0] ?? "" /* MaskExpression.EMPTY_STRING */;
138 const separatorLimit = this.separatorLimit.replace(/\s/g, "" /* MaskExpression.EMPTY_STRING */);
139 if (separatorLimit && +separatorLimit) {
140 if (res[0] === "-" /* MaskExpression.MINUS */) {
141 res = `-${res.slice(1, res.length).slice(0, separatorLimit.length)}`;
142 }
143 else {
144 res = res.slice(0, separatorLimit.length);
145 }
146 }
147 const rgx = /(\d+)(\d{3})/;
148 while (thousandSeparatorChar && rgx.test(res)) {
149 res = res.replace(rgx, '$1' + thousandSeparatorChar + '$2');
150 }
151 if (precision === undefined) {
152 return res + decimals;
153 }
154 else if (precision === 0) {
155 return res;
156 }
157 return res + decimals.substring(0, precision + 1);
158 };
159 this.percentage = (str) => {
160 const sanitizedStr = str.replace(',', '.');
161 const value = Number(this.allowNegativeNumbers && str.includes("-" /* MaskExpression.MINUS */)
162 ? sanitizedStr.slice(1, str.length)
163 : sanitizedStr);
164 return !isNaN(value) && value >= 0 && value <= 100;
165 };
166 this.getPrecision = (maskExpression) => {
167 const x = maskExpression.split("." /* MaskExpression.DOT */);
168 if (x.length > 1) {
169 return Number(x[x.length - 1]);
170 }
171 return Infinity;
172 };
173 this.checkAndRemoveSuffix = (inputValue) => {
174 for (let i = this.suffix?.length - 1; i >= 0; i--) {
175 const substr = this.suffix.substring(i, this.suffix?.length);
176 if (inputValue.includes(substr) &&
177 i !== this.suffix?.length - 1 &&
178 (i - 1 < 0 ||
179 !inputValue.includes(this.suffix.substring(i - 1, this.suffix?.length)))) {
180 return inputValue.replace(substr, "" /* MaskExpression.EMPTY_STRING */);
181 }
182 }
183 return inputValue;
184 };
185 this.checkInputPrecision = (inputValue, precision, decimalMarker) => {
186 if (precision < Infinity) {
187 // TODO need think about decimalMarker
188 if (Array.isArray(decimalMarker)) {
189 const marker = decimalMarker.find((dm) => dm !== this.thousandSeparator);
190 decimalMarker = marker ? marker : decimalMarker[0];
191 }
192 const precisionRegEx = new RegExp(this._charToRegExpExpression(decimalMarker) + `\\d{${precision}}.*$`);
193 const precisionMatch = inputValue.match(precisionRegEx);
194 const precisionMatchLength = (precisionMatch && precisionMatch[0]?.length) ?? 0;
195 if (precisionMatchLength - 1 > precision) {
196 const diff = precisionMatchLength - 1 - precision;
197 inputValue = inputValue.substring(0, inputValue.length - diff);
198 }
199 if (precision === 0 &&
200 this._compareOrIncludes(inputValue[inputValue.length - 1], decimalMarker, this.thousandSeparator)) {
201 inputValue = inputValue.substring(0, inputValue.length - 1);
202 }
203 }
204 return inputValue;
205 };
206 }
207 applyMaskWithPattern(inputValue, maskAndPattern) {
208 const [mask, customPattern] = maskAndPattern;
209 this.customPattern = customPattern;
210 return this.applyMask(inputValue, mask);
211 }
212 applyMask(inputValue, maskExpression, position = 0, justPasted = false, backspaced = false,
213 // eslint-disable-next-line @typescript-eslint/no-explicit-any
214 cb = () => { }) {
215 if (!maskExpression || typeof inputValue !== 'string') {
216 return "" /* MaskExpression.EMPTY_STRING */;
217 }
218 let cursor = 0;
219 let result = '';
220 let multi = false;
221 let backspaceShift = false;
222 let shift = 1;
223 let stepBack = false;
224 if (inputValue.slice(0, this.prefix.length) === this.prefix) {
225 inputValue = inputValue.slice(this.prefix.length, inputValue.length);
226 }
227 if (!!this.suffix && inputValue?.length > 0) {
228 inputValue = this.checkAndRemoveSuffix(inputValue);
229 }
230 if (inputValue === '(' && this.prefix) {
231 inputValue = '';
232 }
233 const inputArray = inputValue.toString().split("" /* MaskExpression.EMPTY_STRING */);
234 if (this.allowNegativeNumbers &&
235 inputValue.slice(cursor, cursor + 1) === "-" /* MaskExpression.MINUS */) {
236 result += inputValue.slice(cursor, cursor + 1);
237 }
238 if (maskExpression === "IP" /* MaskExpression.IP */) {
239 const valuesIP = inputValue.split("." /* MaskExpression.DOT */);
240 this.ipError = this._validIP(valuesIP);
241 maskExpression = '099.099.099.099';
242 }
243 const arr = [];
244 for (let i = 0; i < inputValue.length; i++) {
245 if (inputValue[i]?.match('\\d')) {
246 arr.push(inputValue[i] ?? "" /* MaskExpression.EMPTY_STRING */);
247 }
248 }
249 if (maskExpression === "CPF_CNPJ" /* MaskExpression.CPF_CNPJ */) {
250 this.cpfCnpjError = arr.length !== 11 && arr.length !== 14;
251 if (arr.length > 11) {
252 maskExpression = '00.000.000/0000-00';
253 }
254 else {
255 maskExpression = '000.000.000-00';
256 }
257 }
258 if (maskExpression.startsWith("percent" /* MaskExpression.PERCENT */)) {
259 if (inputValue.match('[a-z]|[A-Z]') ||
260 // eslint-disable-next-line no-useless-escape
261 (inputValue.match(/[-!$%^&*()_+|~=`{}\[\]:";'<>?,\/.]/) && !backspaced)) {
262 inputValue = this._stripToDecimal(inputValue);
263 const precision = this.getPrecision(maskExpression);
264 inputValue = this.checkInputPrecision(inputValue, precision, this.decimalMarker);
265 }
266 const decimalMarker = typeof this.decimalMarker === 'string' ? this.decimalMarker : "." /* MaskExpression.DOT */;
267 if (inputValue.indexOf(decimalMarker) > 0 &&
268 !this.percentage(inputValue.substring(0, inputValue.indexOf(decimalMarker)))) {
269 let base = inputValue.substring(0, inputValue.indexOf(decimalMarker) - 1);
270 if (this.allowNegativeNumbers &&
271 inputValue.slice(cursor, cursor + 1) === "-" /* MaskExpression.MINUS */ &&
272 !backspaced) {
273 base = inputValue.substring(0, inputValue.indexOf(decimalMarker));
274 }
275 inputValue = `${base}${inputValue.substring(inputValue.indexOf(decimalMarker), inputValue.length)}`;
276 }
277 let value = '';
278 this.allowNegativeNumbers &&
279 inputValue.slice(cursor, cursor + 1) === "-" /* MaskExpression.MINUS */
280 ? (value = `${"-" /* MaskExpression.MINUS */}${inputValue.slice(cursor + 1, cursor + inputValue.length)}`)
281 : (value = inputValue);
282 if (this.percentage(value)) {
283 result = this._splitPercentZero(inputValue);
284 }
285 else {
286 result = this._splitPercentZero(inputValue.substring(0, inputValue.length - 1));
287 }
288 }
289 else if (maskExpression.startsWith("separator" /* MaskExpression.SEPARATOR */)) {
290 if (inputValue.match('[wа-яА-Я]') ||
291 inputValue.match('[ЁёА-я]') ||
292 inputValue.match('[a-z]|[A-Z]') ||
293 inputValue.match(/[-@#!$%\\^&*()_£¬'+|~=`{}\]:";<>.?/]/) ||
294 inputValue.match('[^A-Za-z0-9,]')) {
295 inputValue = this._stripToDecimal(inputValue);
296 }
297 const precision = this.getPrecision(maskExpression);
298 const decimalMarker = Array.isArray(this.decimalMarker)
299 ? "." /* MaskExpression.DOT */
300 : this.decimalMarker;
301 if (precision === 0) {
302 inputValue = this.allowNegativeNumbers
303 ? inputValue.length > 2 &&
304 inputValue[0] === "-" /* MaskExpression.MINUS */ &&
305 inputValue[1] === "0" /* MaskExpression.NUMBER_ZERO */ &&
306 inputValue[2] !== this.thousandSeparator &&
307 inputValue[2] !== "," /* MaskExpression.COMMA */ &&
308 inputValue[2] !== "." /* MaskExpression.DOT */
309 ? '-' + inputValue.slice(2, inputValue.length)
310 : inputValue[0] === "0" /* MaskExpression.NUMBER_ZERO */ &&
311 inputValue.length > 1 &&
312 inputValue[1] !== this.thousandSeparator &&
313 inputValue[1] !== "," /* MaskExpression.COMMA */ &&
314 inputValue[1] !== "." /* MaskExpression.DOT */
315 ? inputValue.slice(1, inputValue.length)
316 : inputValue
317 : inputValue.length > 1 &&
318 inputValue[0] === "0" /* MaskExpression.NUMBER_ZERO */ &&
319 inputValue[1] !== this.thousandSeparator &&
320 inputValue[1] !== "," /* MaskExpression.COMMA */ &&
321 inputValue[1] !== "." /* MaskExpression.DOT */
322 ? inputValue.slice(1, inputValue.length)
323 : inputValue;
324 }
325 else {
326 if (inputValue[0] === decimalMarker && inputValue.length > 1) {
327 inputValue =
328 "0" /* MaskExpression.NUMBER_ZERO */ + inputValue.slice(0, inputValue.length + 1);
329 this.plusOnePosition = true;
330 }
331 if (inputValue[0] === "0" /* MaskExpression.NUMBER_ZERO */ &&
332 inputValue[1] !== decimalMarker &&
333 inputValue[1] !== this.thousandSeparator) {
334 inputValue =
335 inputValue.length > 1
336 ? inputValue.slice(0, 1) +
337 decimalMarker +
338 inputValue.slice(1, inputValue.length + 1)
339 : inputValue;
340 this.plusOnePosition = true;
341 }
342 if (this.allowNegativeNumbers &&
343 inputValue[0] === "-" /* MaskExpression.MINUS */ &&
344 (inputValue[1] === decimalMarker ||
345 inputValue[1] === "0" /* MaskExpression.NUMBER_ZERO */)) {
346 inputValue =
347 inputValue[1] === decimalMarker && inputValue.length > 2
348 ? inputValue.slice(0, 1) +
349 "0" /* MaskExpression.NUMBER_ZERO */ +
350 inputValue.slice(1, inputValue.length)
351 : inputValue[1] === "0" /* MaskExpression.NUMBER_ZERO */ &&
352 inputValue.length > 2 &&
353 inputValue[2] !== decimalMarker
354 ? inputValue.slice(0, 2) +
355 decimalMarker +
356 inputValue.slice(2, inputValue.length)
357 : inputValue;
358 this.plusOnePosition = true;
359 }
360 }
361 if (backspaced) {
362 const inputValueAfterZero = inputValue.slice(this._findFirstNonZeroDigitIndex(inputValue), inputValue.length);
363 const positionOfZeroOrDecimalMarker = inputValue[position] === "0" /* MaskExpression.NUMBER_ZERO */ ||
364 inputValue[position] === decimalMarker;
365 const zeroIndexNumberZero = inputValue[0] === "0" /* MaskExpression.NUMBER_ZERO */;
366 const zeroIndexMinus = inputValue[0] === "-" /* MaskExpression.MINUS */;
367 const zeroIndexThousand = inputValue[0] === this.thousandSeparator;
368 const firstIndexDecimalMarker = inputValue[1] === decimalMarker;
369 const firstIndexNumberZero = inputValue[1] === "0" /* MaskExpression.NUMBER_ZERO */;
370 const secondIndexDecimalMarker = inputValue[2] === decimalMarker;
371 if (zeroIndexNumberZero &&
372 firstIndexDecimalMarker &&
373 positionOfZeroOrDecimalMarker &&
374 position < 2) {
375 inputValue = inputValueAfterZero;
376 }
377 if (zeroIndexMinus &&
378 firstIndexNumberZero &&
379 secondIndexDecimalMarker &&
380 positionOfZeroOrDecimalMarker &&
381 position < 3) {
382 inputValue = "-" /* MaskExpression.MINUS */ + inputValueAfterZero;
383 }
384 if (inputValueAfterZero !== "-" /* MaskExpression.MINUS */ &&
385 ((position === 0 && (zeroIndexNumberZero || zeroIndexThousand)) ||
386 (this.allowNegativeNumbers &&
387 position === 1 &&
388 zeroIndexMinus &&
389 !firstIndexNumberZero))) {
390 inputValue = zeroIndexMinus
391 ? "-" /* MaskExpression.MINUS */ + inputValueAfterZero
392 : inputValueAfterZero;
393 }
394 }
395 // TODO: we had different rexexps here for the different cases... but tests dont seam to bother - check this
396 // separator: no COMMA, dot-sep: no SPACE, COMMA OK, comma-sep: no SPACE, COMMA OK
397 const thousandSeparatorCharEscaped = this._charToRegExpExpression(this.thousandSeparator);
398 let invalidChars = '@#!$%^&*()_+|~=`{}\\[\\]:\\s,\\.";<>?\\/'.replace(thousandSeparatorCharEscaped, '');
399 //.replace(decimalMarkerEscaped, '');
400 if (Array.isArray(this.decimalMarker)) {
401 for (const marker of this.decimalMarker) {
402 invalidChars = invalidChars.replace(this._charToRegExpExpression(marker), "" /* MaskExpression.EMPTY_STRING */);
403 }
404 }
405 else {
406 invalidChars = invalidChars.replace(this._charToRegExpExpression(this.decimalMarker), '');
407 }
408 const invalidCharRegexp = new RegExp('[' + invalidChars + ']');
409 if (inputValue.match(invalidCharRegexp)) {
410 inputValue = inputValue.substring(0, inputValue.length - 1);
411 }
412 inputValue = this.checkInputPrecision(inputValue, precision, this.decimalMarker);
413 const strForSep = inputValue.replace(new RegExp(thousandSeparatorCharEscaped, 'g'), '');
414 result = this._formatWithSeparators(strForSep, this.thousandSeparator, this.decimalMarker, precision);
415 const commaShift = result.indexOf("," /* MaskExpression.COMMA */) - inputValue.indexOf("," /* MaskExpression.COMMA */);
416 const shiftStep = result.length - inputValue.length;
417 if (result[position - 1] === this.thousandSeparator && this.prefix && backspaced) {
418 position = position - 1;
419 }
420 else if (shiftStep > 0 && result[position] !== this.thousandSeparator) {
421 backspaceShift = true;
422 let _shift = 0;
423 do {
424 this._shift.add(position + _shift);
425 _shift++;
426 } while (_shift < shiftStep);
427 }
428 else if (result[position - 1] === this.decimalMarker ||
429 shiftStep === -4 ||
430 shiftStep === -3 ||
431 result[position] === this.thousandSeparator) {
432 this._shift.clear();
433 this._shift.add(position - 1);
434 }
435 else if ((commaShift !== 0 &&
436 position > 0 &&
437 !(result.indexOf("," /* MaskExpression.COMMA */) >= position && position > 3)) ||
438 (!(result.indexOf("." /* MaskExpression.DOT */) >= position && position > 3) &&
439 shiftStep <= 0)) {
440 this._shift.clear();
441 backspaceShift = true;
442 shift = shiftStep;
443 position += shiftStep;
444 this._shift.add(position);
445 }
446 else {
447 this._shift.clear();
448 }
449 }
450 else {
451 for (let i = 0, inputSymbol = inputArray[0]; i < inputArray.length; i++, inputSymbol = inputArray[i] ?? "" /* MaskExpression.EMPTY_STRING */) {
452 if (cursor === maskExpression.length) {
453 break;
454 }
455 const symbolStarInPattern = "*" /* MaskExpression.SYMBOL_STAR */ in this.patterns;
456 if (this._checkSymbolMask(inputSymbol, maskExpression[cursor] ?? "" /* MaskExpression.EMPTY_STRING */) &&
457 maskExpression[cursor + 1] === "?" /* MaskExpression.SYMBOL_QUESTION */) {
458 result += inputSymbol;
459 cursor += 2;
460 }
461 else if (maskExpression[cursor + 1] === "*" /* MaskExpression.SYMBOL_STAR */ &&
462 multi &&
463 this._checkSymbolMask(inputSymbol, maskExpression[cursor + 2] ?? "" /* MaskExpression.EMPTY_STRING */)) {
464 result += inputSymbol;
465 cursor += 3;
466 multi = false;
467 }
468 else if (this._checkSymbolMask(inputSymbol, maskExpression[cursor] ?? "" /* MaskExpression.EMPTY_STRING */) &&
469 maskExpression[cursor + 1] === "*" /* MaskExpression.SYMBOL_STAR */ &&
470 !symbolStarInPattern) {
471 result += inputSymbol;
472 multi = true;
473 }
474 else if (maskExpression[cursor + 1] === "?" /* MaskExpression.SYMBOL_QUESTION */ &&
475 this._checkSymbolMask(inputSymbol, maskExpression[cursor + 2] ?? "" /* MaskExpression.EMPTY_STRING */)) {
476 result += inputSymbol;
477 cursor += 3;
478 }
479 else if (this._checkSymbolMask(inputSymbol, maskExpression[cursor] ?? "" /* MaskExpression.EMPTY_STRING */)) {
480 if (maskExpression[cursor] === "H" /* MaskExpression.HOURS */) {
481 if (this.apm ? Number(inputSymbol) > 9 : Number(inputSymbol) > 2) {
482 position = !this.leadZeroDateTime ? position + 1 : position;
483 cursor += 1;
484 this._shiftStep(maskExpression, cursor, inputArray.length);
485 i--;
486 if (this.leadZeroDateTime) {
487 result += '0';
488 }
489 continue;
490 }
491 }
492 if (maskExpression[cursor] === "h" /* MaskExpression.HOUR */) {
493 if (this.apm
494 ? (result.length === 1 && Number(result) > 1) ||
495 (result === '1' && Number(inputSymbol) > 2) ||
496 (inputValue.slice(cursor - 1, cursor).length === 1 &&
497 Number(inputValue.slice(cursor - 1, cursor)) > 2) ||
498 (inputValue.slice(cursor - 1, cursor) === '1' &&
499 Number(inputSymbol) > 2)
500 : (result === '2' && Number(inputSymbol) > 3) ||
501 ((result.slice(cursor - 2, cursor) === '2' ||
502 result.slice(cursor - 3, cursor) === '2' ||
503 result.slice(cursor - 4, cursor) === '2' ||
504 result.slice(cursor - 1, cursor) === '2') &&
505 Number(inputSymbol) > 3 &&
506 cursor > 10)) {
507 position = position + 1;
508 cursor += 1;
509 i--;
510 continue;
511 }
512 }
513 if (maskExpression[cursor] === "m" /* MaskExpression.MINUTE */ ||
514 maskExpression[cursor] === "s" /* MaskExpression.SECOND */) {
515 if (Number(inputSymbol) > 5) {
516 position = !this.leadZeroDateTime ? position + 1 : position;
517 cursor += 1;
518 this._shiftStep(maskExpression, cursor, inputArray.length);
519 i--;
520 if (this.leadZeroDateTime) {
521 result += '0';
522 }
523 continue;
524 }
525 }
526 const daysCount = 31;
527 const inputValueCursor = inputValue[cursor];
528 const inputValueCursorPlusOne = inputValue[cursor + 1];
529 const inputValueCursorPlusTwo = inputValue[cursor + 2];
530 const inputValueCursorMinusOne = inputValue[cursor - 1];
531 const inputValueCursorMinusTwo = inputValue[cursor - 2];
532 const inputValueSliceMinusThreeMinusOne = inputValue.slice(cursor - 3, cursor - 1);
533 const inputValueSliceMinusOnePlusOne = inputValue.slice(cursor - 1, cursor + 1);
534 const inputValueSliceCursorPlusTwo = inputValue.slice(cursor, cursor + 2);
535 const inputValueSliceMinusTwoCursor = inputValue.slice(cursor - 2, cursor);
536 if (maskExpression[cursor] === "d" /* MaskExpression.DAY */) {
537 const maskStartWithMonth = maskExpression.slice(0, 2) === "M0" /* MaskExpression.MONTHS */;
538 const startWithMonthInput = maskExpression.slice(0, 2) === "M0" /* MaskExpression.MONTHS */ &&
539 this.specialCharacters.includes(inputValueCursorMinusTwo);
540 if ((Number(inputSymbol) > 3 && this.leadZeroDateTime) ||
541 (!maskStartWithMonth &&
542 (Number(inputValueSliceCursorPlusTwo) > daysCount ||
543 Number(inputValueSliceMinusOnePlusOne) > daysCount ||
544 this.specialCharacters.includes(inputValueCursorPlusOne))) ||
545 (startWithMonthInput
546 ? Number(inputValueSliceMinusOnePlusOne) > daysCount ||
547 (!this.specialCharacters.includes(inputValueCursor) &&
548 this.specialCharacters.includes(inputValueCursorPlusTwo)) ||
549 this.specialCharacters.includes(inputValueCursor)
550 : Number(inputValueSliceCursorPlusTwo) > daysCount ||
551 this.specialCharacters.includes(inputValueCursorPlusOne))) {
552 position = !this.leadZeroDateTime ? position + 1 : position;
553 cursor += 1;
554 this._shiftStep(maskExpression, cursor, inputArray.length);
555 i--;
556 if (this.leadZeroDateTime) {
557 result += '0';
558 }
559 continue;
560 }
561 }
562 if (maskExpression[cursor] === "M" /* MaskExpression.MONTH */) {
563 const monthsCount = 12;
564 // mask without day
565 const withoutDays = cursor === 0 &&
566 (Number(inputSymbol) > 2 ||
567 Number(inputValueSliceCursorPlusTwo) > monthsCount ||
568 (this.specialCharacters.includes(inputValueCursorPlusOne) &&
569 !backspaced));
570 // day<10 && month<12 for input
571 const specialChart = maskExpression.slice(cursor + 2, cursor + 3);
572 const day1monthInput = inputValueSliceMinusThreeMinusOne.includes(specialChart) &&
573 maskExpression.includes('d0') &&
574 ((this.specialCharacters.includes(inputValueCursorMinusTwo) &&
575 Number(inputValueSliceMinusOnePlusOne) > monthsCount &&
576 !this.specialCharacters.includes(inputValueCursor)) ||
577 this.specialCharacters.includes(inputValueCursor));
578 // month<12 && day<10 for input
579 const day2monthInput = Number(inputValueSliceMinusThreeMinusOne) <= daysCount &&
580 !this.specialCharacters.includes(inputValueSliceMinusThreeMinusOne) &&
581 this.specialCharacters.includes(inputValueCursorMinusOne) &&
582 (Number(inputValueSliceCursorPlusTwo) > monthsCount ||
583 this.specialCharacters.includes(inputValueCursorPlusOne));
584 // cursor === 5 && without days
585 const day2monthInputDot = (Number(inputValueSliceCursorPlusTwo) > monthsCount && cursor === 5) ||
586 (this.specialCharacters.includes(inputValueCursorPlusOne) &&
587 cursor === 5);
588 // // day<10 && month<12 for paste whole data
589 const day1monthPaste = Number(inputValueSliceMinusThreeMinusOne) > daysCount &&
590 !this.specialCharacters.includes(inputValueSliceMinusThreeMinusOne) &&
591 !this.specialCharacters.includes(inputValueSliceMinusTwoCursor) &&
592 Number(inputValueSliceMinusTwoCursor) > monthsCount &&
593 maskExpression.includes('d0');
594 // 10<day<31 && month<12 for paste whole data
595 const day2monthPaste = Number(inputValueSliceMinusThreeMinusOne) <= daysCount &&
596 !this.specialCharacters.includes(inputValueSliceMinusThreeMinusOne) &&
597 !this.specialCharacters.includes(inputValueCursorMinusOne) &&
598 Number(inputValueSliceMinusOnePlusOne) > monthsCount;
599 if ((Number(inputSymbol) > 1 && this.leadZeroDateTime) ||
600 withoutDays ||
601 day1monthInput ||
602 day2monthPaste ||
603 day1monthPaste ||
604 day2monthInput ||
605 (day2monthInputDot && !this.leadZeroDateTime)) {
606 position = !this.leadZeroDateTime ? position + 1 : position;
607 cursor += 1;
608 this._shiftStep(maskExpression, cursor, inputArray.length);
609 i--;
610 if (this.leadZeroDateTime) {
611 result += '0';
612 }
613 continue;
614 }
615 }
616 result += inputSymbol;
617 cursor++;
618 }
619 else if (this.specialCharacters.includes(inputSymbol) &&
620 maskExpression[cursor] === inputSymbol) {
621 result += inputSymbol;
622 cursor++;
623 }
624 else if (this.specialCharacters.indexOf(maskExpression[cursor] ?? "" /* MaskExpression.EMPTY_STRING */) !== -1) {
625 result += maskExpression[cursor];
626 cursor++;
627 this._shiftStep(maskExpression, cursor, inputArray.length);
628 i--;
629 }
630 else if (maskExpression[cursor] === "9" /* MaskExpression.NUMBER_NINE */ &&
631 this.showMaskTyped) {
632 this._shiftStep(maskExpression, cursor, inputArray.length);
633 }
634 else if (this.patterns[maskExpression[cursor] ?? "" /* MaskExpression.EMPTY_STRING */] &&
635 this.patterns[maskExpression[cursor] ?? "" /* MaskExpression.EMPTY_STRING */]?.optional) {
636 if (!!inputArray[cursor] &&
637 maskExpression !== '099.099.099.099' &&
638 maskExpression !== '000.000.000-00' &&
639 maskExpression !== '00.000.000/0000-00' &&
640 !maskExpression.match(/^9+\.0+$/) &&
641 !this.patterns[maskExpression[cursor] ?? "" /* MaskExpression.EMPTY_STRING */]
642 ?.optional) {
643 result += inputArray[cursor];
644 }
645 if (maskExpression.includes("9" /* MaskExpression.NUMBER_NINE */ + "*" /* MaskExpression.SYMBOL_STAR */) &&
646 maskExpression.includes("0" /* MaskExpression.NUMBER_ZERO */ + "*" /* MaskExpression.SYMBOL_STAR */)) {
647 cursor++;
648 }
649 cursor++;
650 i--;
651 }
652 else if (this.maskExpression[cursor + 1] === "*" /* MaskExpression.SYMBOL_STAR */ &&
653 this._findSpecialChar(this.maskExpression[cursor + 2] ?? "" /* MaskExpression.EMPTY_STRING */) &&
654 this._findSpecialChar(inputSymbol) === this.maskExpression[cursor + 2] &&
655 multi) {
656 cursor += 3;
657 result += inputSymbol;
658 }
659 else if (this.maskExpression[cursor + 1] === "?" /* MaskExpression.SYMBOL_QUESTION */ &&
660 this._findSpecialChar(this.maskExpression[cursor + 2] ?? "" /* MaskExpression.EMPTY_STRING */) &&
661 this._findSpecialChar(inputSymbol) === this.maskExpression[cursor + 2] &&
662 multi) {
663 cursor += 3;
664 result += inputSymbol;
665 }
666 else if (this.showMaskTyped &&
667 this.specialCharacters.indexOf(inputSymbol) < 0 &&
668 inputSymbol !== this.placeHolderCharacter &&
669 this.placeHolderCharacter.length === 1) {
670 stepBack = true;
671 }
672 }
673 }
674 if (result.length + 1 === maskExpression.length &&
675 this.specialCharacters.indexOf(maskExpression[maskExpression.length - 1] ?? "" /* MaskExpression.EMPTY_STRING */) !== -1) {
676 result += maskExpression[maskExpression.length - 1];
677 }
678 let newPosition = position + 1;
679 while (this._shift.has(newPosition)) {
680 shift++;
681 newPosition++;
682 }
683 let actualShift = justPasted && !maskExpression.startsWith("separator" /* MaskExpression.SEPARATOR */)
684 ? cursor
685 : this._shift.has(position)
686 ? shift
687 : 0;
688 if (stepBack) {
689 actualShift--;
690 }
691 cb(actualShift, backspaceShift);
692 if (shift < 0) {
693 this._shift.clear();
694 }
695 let onlySpecial = false;
696 if (backspaced) {
697 onlySpecial = inputArray.every((char) => this.specialCharacters.includes(char));
698 }
699 let res = `${this.prefix}${onlySpecial ? "" /* MaskExpression.EMPTY_STRING */ : result}${this.showMaskTyped ? '' : this.suffix}`;
700 if (result.length === 0) {
701 res = !this.dropSpecialCharacters ? `${this.prefix}${result}` : `${result}`;
702 }
703 const isSpecialCharacterMaskFirstSymbol = inputValue.length === 1 &&
704 this.specialCharacters.includes(maskExpression[0]) &&
705 inputValue !== maskExpression[0];
706 if (!this._checkSymbolMask(inputValue, maskExpression[1]) &&
707 isSpecialCharacterMaskFirstSymbol) {
708 return '';
709 }
710 if (result.includes("-" /* MaskExpression.MINUS */) && this.prefix && this.allowNegativeNumbers) {
711 if (backspaced && result === "-" /* MaskExpression.MINUS */) {
712 return '';
713 }
714 res = `${"-" /* MaskExpression.MINUS */}${this.prefix}${result
715 .split("-" /* MaskExpression.MINUS */)
716 .join("" /* MaskExpression.EMPTY_STRING */)}${this.suffix}`;
717 }
718 return res;
719 }
720 _findDropSpecialChar(inputSymbol) {
721 if (Array.isArray(this.dropSpecialCharacters)) {
722 return this.dropSpecialCharacters.find((val) => val === inputSymbol);
723 }
724 return this._findSpecialChar(inputSymbol);
725 }
726 _findSpecialChar(inputSymbol) {
727 return this.specialCharacters.find((val) => val === inputSymbol);
728 }
729 _checkSymbolMask(inputSymbol, maskSymbol) {
730 this.patterns = this.customPattern ? this.customPattern : this.patterns;
731 return ((this.patterns[maskSymbol]?.pattern &&
732 this.patterns[maskSymbol]?.pattern.test(inputSymbol)) ??
733 false);
734 }
735 _stripToDecimal(str) {
736 return str
737 .split("" /* MaskExpression.EMPTY_STRING */)
738 .filter((i, idx) => {
739 const isDecimalMarker = typeof this.decimalMarker === 'string'
740 ? i === this.decimalMarker
741 : // TODO (inepipenko) use utility type
742 this.decimalMarker.includes(i);
743 return (i.match('^-?\\d') ||
744 i === this.thousandSeparator ||
745 isDecimalMarker ||
746 (i === "-" /* MaskExpression.MINUS */ && idx === 0 && this.allowNegativeNumbers));
747 })
748 .join("" /* MaskExpression.EMPTY_STRING */);
749 }
750 _charToRegExpExpression(char) {
751 // if (Array.isArray(char)) {
752 // return char.map((v) => ('[\\^$.|?*+()'.indexOf(v) >= 0 ? `\\${v}` : v)).join('|');
753 // }
754 if (char) {
755 const charsToEscape = '[\\^$.|?*+()';
756 return char === ' ' ? '\\s' : charsToEscape.indexOf(char) >= 0 ? `\\${char}` : char;
757 }
758 return char;
759 }
760 _shiftStep(maskExpression, cursor, inputLength) {
761 const shiftStep = /[*?]/g.test(maskExpression.slice(0, cursor))
762 ? inputLength
763 : cursor;
764 this._shift.add(shiftStep + this.prefix.length || 0);
765 }
766 _compareOrIncludes(value, comparedValue, excludedValue) {
767 return Array.isArray(comparedValue)
768 ? comparedValue.filter((v) => v !== excludedValue).includes(value)
769 : value === comparedValue;
770 }
771 _validIP(valuesIP) {
772 return !(valuesIP.length === 4 &&
773 !valuesIP.some((value, index) => {
774 if (valuesIP.length !== index + 1) {
775 return value === "" /* MaskExpression.EMPTY_STRING */ || Number(value) > 255;
776 }
777 return value === "" /* MaskExpression.EMPTY_STRING */ || Number(value.substring(0, 3)) > 255;
778 }));
779 }
780 _splitPercentZero(value) {
781 if (value === "-" /* MaskExpression.MINUS */ && this.allowNegativeNumbers) {
782 return value;
783 }
784 const decimalIndex = typeof this.decimalMarker === 'string'
785 ? value.indexOf(this.decimalMarker)
786 : value.indexOf("." /* MaskExpression.DOT */);
787 const emptyOrMinus = this.allowNegativeNumbers && value.includes("-" /* MaskExpression.MINUS */) ? '-' : '';
788 if (decimalIndex === -1) {
789 const parsedValue = parseInt(emptyOrMinus ? value.slice(1, value.length) : value, 10);
790 return isNaN(parsedValue)
791 ? "" /* MaskExpression.EMPTY_STRING */
792 : `${emptyOrMinus}${parsedValue}`;
793 }
794 else {
795 const integerPart = parseInt(value.replace('-', '').substring(0, decimalIndex), 10);
796 const decimalPart = value.substring(decimalIndex + 1);
797 const integerString = isNaN(integerPart) ? '' : integerPart.toString();
798 const decimal = typeof this.decimalMarker === 'string' ? this.decimalMarker : "." /* MaskExpression.DOT */;
799 return integerString === "" /* MaskExpression.EMPTY_STRING */
800 ? "" /* MaskExpression.EMPTY_STRING */
801 : `${emptyOrMinus}${integerString}${decimal}${decimalPart}`;
802 }
803 }
804 _findFirstNonZeroDigitIndex(inputString) {
805 for (let i = 0; i < inputString.length; i++) {
806 const char = inputString[i];
807 if (char && char >= '1' && char <= '9') {
808 return i;
809 }
810 }
811 return -1;
812 }
813 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.1", ngImport: i0, type: NgxMaskApplierService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
814 static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.1.1", ngImport: i0, type: NgxMaskApplierService }); }
815}
816i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.1", ngImport: i0, type: NgxMaskApplierService, decorators: [{
817 type: Injectable
818 }] });
819
820class NgxMaskService extends NgxMaskApplierService {
821 constructor() {
822 super(...arguments);
823 this.isNumberValue = false;
824 this.maskIsShown = '';
825 this.selStart = null;
826 this.selEnd = null;
827 /**
828 * Whether we are currently in writeValue function, in this case when applying the mask we don't want to trigger onChange function,
829 * since writeValue should be a one way only process of writing the DOM value based on the Angular model value.
830 */
831 this.writingValue = false;
832 this.maskChanged = false;
833 this._maskExpressionArray = [];
834 this.triggerOnMaskChange = false;
835 this._previousValue = '';
836 this._currentValue = '';
837 this._emitValue = false;
838 // eslint-disable-next-line @typescript-eslint/no-explicit-any
839 this.onChange = (_) => { };
840 this._elementRef = inject(ElementRef, { optional: true });
841 this.document = inject(DOCUMENT);
842 this._config = inject(NGX_MASK_CONFIG);
843 this._renderer = inject(Renderer2, { optional: true });
844 }
845 applyMask(inputValue, maskExpression, position = 0, justPasted = false, backspaced = false,
846 // eslint-disable-next-line @typescript-eslint/no-explicit-any
847 cb = () => { }) {
848 if (!maskExpression) {
849 return inputValue !== this.actualValue ? this.actualValue : inputValue;
850 }
851 this.maskIsShown = this.showMaskTyped
852 ? this.showMaskInInput()
853 : "" /* MaskExpression.EMPTY_STRING */;
854 if (this.maskExpression === "IP" /* MaskExpression.IP */ && this.showMaskTyped) {
855 this.maskIsShown = this.showMaskInInput(inputValue || "#" /* MaskExpression.HASH */);
856 }
857 if (this.maskExpression === "CPF_CNPJ" /* MaskExpression.CPF_CNPJ */ && this.showMaskTyped) {
858 this.maskIsShown = this.showMaskInInput(inputValue || "#" /* MaskExpression.HASH */);
859 }
860 if (!inputValue && this.showMaskTyped) {
861 this.formControlResult(this.prefix);
862 return `${this.prefix}${this.maskIsShown}${this.suffix}`;
863 }
864 const getSymbol = !!inputValue && typeof this.selStart === 'number'
865 ? (inputValue[this.selStart] ?? "" /* MaskExpression.EMPTY_STRING */)
866 : "" /* MaskExpression.EMPTY_STRING */;
867 let newInputValue = '';
868 if (this.hiddenInput !== undefined && !this.writingValue) {
869 let actualResult = inputValue && inputValue.length === 1
870 ? inputValue.split("" /* MaskExpression.EMPTY_STRING */)
871 : this.actualValue.split("" /* MaskExpression.EMPTY_STRING */);
872 // eslint-disable @typescript-eslint/no-unused-expressions
873 if (typeof this.selStart === 'object' && typeof this.selEnd === 'object') {
874 this.selStart = Number(this.selStart);
875 this.selEnd = Number(this.selEnd);
876 }
877 else {
878 inputValue !== "" /* MaskExpression.EMPTY_STRING */ && actualResult.length
879 ? typeof this.selStart === 'number' && typeof this.selEnd === 'number'
880 ? inputValue.length > actualResult.length
881 ? actualResult.splice(this.selStart, 0, getSymbol)
882 : inputValue.length < actualResult.length
883 ? actualResult.length - inputValue.length === 1
884 ? backspaced
885 ? actualResult.splice(this.selStart - 1, 1)
886 : actualResult.splice(inputValue.length - 1, 1)
887 : actualResult.splice(this.selStart, this.selEnd - this.selStart)
888 : null
889 : null
890 : (actualResult = []);
891 }
892 if (this.showMaskTyped) {
893 if (!this.hiddenInput) {
894 inputValue = this.removeMask(inputValue);
895 }
896 }
897 // eslint-enable @typescript-eslint/no-unused-expressions
898 newInputValue =
899 this.actualValue.length && actualResult.length <= inputValue.length
900 ? this.shiftTypedSymbols(actualResult.join("" /* MaskExpression.EMPTY_STRING */))
901 : inputValue;
902 }
903 if (justPasted && (this.hiddenInput || !this.hiddenInput)) {
904 newInputValue = inputValue;
905 }
906 if (backspaced &&
907 this.specialCharacters.indexOf(this.maskExpression[position] ?? "" /* MaskExpression.EMPTY_STRING */) !== -1 &&
908 this.showMaskTyped &&
909 !this.prefix) {
910 newInputValue = this._currentValue;
911 }
912 if (this.deletedSpecialCharacter && position) {
913 if (this.specialCharacters.includes(this.actualValue.slice(position, position + 1))) {
914 position = position + 1;
915 }
916 else if (maskExpression.slice(position - 1, position + 1) !== "M0" /* MaskExpression.MONTHS */) {
917 position = position - 2;
918 }
919 this.deletedSpecialCharacter = false;
920 }
921 if (this.showMaskTyped &&
922 this.placeHolderCharacter.length === 1 &&
923 !this.leadZeroDateTime) {
924 inputValue = this.removeMask(inputValue);
925 }
926 if (this.maskChanged) {
927 newInputValue = inputValue;
928 }
929 else {
930 newInputValue =
931 Boolean(newInputValue) && newInputValue.length ? newInputValue : inputValue;
932 }
933 if (this.showMaskTyped &&
934 this.keepCharacterPositions &&
935 this.actualValue &&
936 !justPasted &&
937 !this.writingValue) {
938 const value = this.dropSpecialCharacters
939 ? this.removeMask(this.actualValue)
940 : this.actualValue;
941 this.formControlResult(value);
942 return this.actualValue
943 ? this.actualValue
944 : `${this.prefix}${this.maskIsShown}${this.suffix}`;
945 }
946 const result = super.applyMask(newInputValue, maskExpression, position, justPasted, backspaced, cb);
947 this.actualValue = this.getActualValue(result);
948 // handle some separator implications:
949 // a.) adjust decimalMarker default (. -> ,) if thousandSeparator is a dot
950 if (this.thousandSeparator === "." /* MaskExpression.DOT */ &&
951 this.decimalMarker === "." /* MaskExpression.DOT */) {
952 this.decimalMarker = "," /* MaskExpression.COMMA */;
953 }
954 // b) remove decimal marker from list of special characters to mask
955 if (this.maskExpression.startsWith("separator" /* MaskExpression.SEPARATOR */) &&
956 this.dropSpecialCharacters === true) {
957 this.specialCharacters = this.specialCharacters.filter((item) => !this._compareOrIncludes(item, this.decimalMarker, this.thousandSeparator) //item !== this.decimalMarker, // !
958 );
959 }
960 if (result || result === '') {
961 this._previousValue = this._currentValue;
962 this._currentValue = result;
963 this._emitValue =
964 this._previousValue !== this._currentValue ||
965 this.maskChanged ||
966 (this._previousValue === this._currentValue && justPasted);
967 }
968 this._emitValue
969 ? this.writingValue && this.triggerOnMaskChange
970 ? requestAnimationFrame(() => this.formControlResult(result))
971 : this.formControlResult(result)
972 : '';
973 if (!this.showMaskTyped || (this.showMaskTyped && this.hiddenInput)) {
974 if (this.hiddenInput) {
975 if (backspaced) {
976 return this.hideInput(result, this.maskExpression);
977 }
978 return `${this.hideInput(result, this.maskExpression)}${this.maskIsShown.slice(result.length)}`;
979 }
980 return result;
981 }
982 const resLen = result.length;
983 const prefNmask = `${this.prefix}${this.maskIsShown}${this.suffix}`;
984 if (this.maskExpression.includes("H" /* MaskExpression.HOURS */)) {
985 const countSkipedSymbol = this._numberSkipedSymbols(result);
986 return `${result}${prefNmask.slice(resLen + countSkipedSymbol)}`;
987 }
988 else if (this.maskExpression === "IP" /* MaskExpression.IP */ ||
989 this.maskExpression === "CPF_CNPJ" /* MaskExpression.CPF_CNPJ */) {
990 return `${result}${prefNmask}`;
991 }
992 return `${result}${prefNmask.slice(resLen)}`;
993 }
994 // get the number of characters that were shifted
995 _numberSkipedSymbols(value) {
996 const regex = /(^|\D)(\d\D)/g;
997 let match = regex.exec(value);
998 let countSkipedSymbol = 0;
999 while (match != null) {
1000 countSkipedSymbol += 1;
1001 match = regex.exec(value);
1002 }
1003 return countSkipedSymbol;
1004 }
1005 applyValueChanges(position, justPasted, backspaced,
1006 // eslint-disable-next-line @typescript-eslint/no-explicit-any
1007 cb = () => { }) {
1008 const formElement = this._elementRef?.nativeElement;
1009 if (!formElement) {
1010 return;
1011 }
1012 formElement.value = this.applyMask(formElement.value, this.maskExpression, position, justPasted, backspaced, cb);
1013 if (formElement === this._getActiveElement()) {
1014 return;
1015 }
1016 this.clearIfNotMatchFn();
1017 }
1018 hideInput(inputValue, maskExpression) {
1019 return inputValue
1020 .split("" /* MaskExpression.EMPTY_STRING */)
1021 .map((curr, index) => {
1022 if (this.patterns &&
1023 this.patterns[maskExpression[index] ?? "" /* MaskExpression.EMPTY_STRING */] &&
1024 this.patterns[maskExpression[index] ?? "" /* MaskExpression.EMPTY_STRING */]?.symbol) {
1025 return this.patterns[maskExpression[index] ?? "" /* MaskExpression.EMPTY_STRING */]
1026 ?.symbol;
1027 }
1028 return curr;
1029 })
1030 .join("" /* MaskExpression.EMPTY_STRING */);
1031 }
1032 // this function is not necessary, it checks result against maskExpression
1033 getActualValue(res) {
1034 const compare = res
1035 .split("" /* MaskExpression.EMPTY_STRING */)
1036 .filter((symbol, i) => {
1037 const maskChar = this.maskExpression[i] ?? "" /* MaskExpression.EMPTY_STRING */;
1038 return (this._checkSymbolMask(symbol, maskChar) ||
1039 (this.specialCharacters.includes(maskChar) && symbol === maskChar));
1040 });
1041 if (compare.join("" /* MaskExpression.EMPTY_STRING */) === res) {
1042 return compare.join("" /* MaskExpression.EMPTY_STRING */);
1043 }
1044 return res;
1045 }
1046 shiftTypedSymbols(inputValue) {
1047 let symbolToReplace = '';
1048 const newInputValue = (inputValue &&
1049 inputValue
1050 .split("" /* MaskExpression.EMPTY_STRING */)
1051 .map((currSymbol, index) => {
1052 if (this.specialCharacters.includes(inputValue[index + 1] ?? "" /* MaskExpression.EMPTY_STRING */) &&
1053 inputValue[index + 1] !== this.maskExpression[index + 1]) {
1054 symbolToReplace = currSymbol;
1055 return inputValue[index + 1];
1056 }
1057 if (symbolToReplace.length) {
1058 const replaceSymbol = symbolToReplace;
1059 symbolToReplace = "" /* MaskExpression.EMPTY_STRING */;
1060 return replaceSymbol;
1061 }
1062 return currSymbol;
1063 })) ||
1064 [];
1065 return newInputValue.join("" /* MaskExpression.EMPTY_STRING */);
1066 }
1067 /**
1068 * Convert number value to string
1069 * 3.1415 -> '3.1415'
1070 * 1e-7 -> '0.0000001'
1071 */
1072 numberToString(value) {
1073 if ((!value && value !== 0) ||
1074 (this.maskExpression.startsWith("separator" /* MaskExpression.SEPARATOR */) &&
1075 (this.leadZero || !this.dropSpecialCharacters)) ||
1076 (this.maskExpression.startsWith("separator" /* MaskExpression.SEPARATOR */) &&
1077 this.separatorLimit.length > 14 &&
1078 String(value).length > 14)) {
1079 return String(value);
1080 }
1081 return Number(value)
1082 .toLocaleString('fullwide', {
1083 useGrouping: false,
1084 maximumFractionDigits: 20,
1085 })
1086 .replace(`/${"-" /* MaskExpression.MINUS */}/`, "-" /* MaskExpression.MINUS */);
1087 }
1088 showMaskInInput(inputVal) {
1089 if (this.showMaskTyped && !!this.shownMaskExpression) {
1090 if (this.maskExpression.length !== this.shownMaskExpression.length) {
1091 throw new Error('Mask expression must match mask placeholder length');
1092 }
1093 else {
1094 return this.shownMaskExpression;
1095 }
1096 }
1097 else if (this.showMaskTyped) {
1098 if (inputVal) {
1099 if (this.maskExpression === "IP" /* MaskExpression.IP */) {
1100 return this._checkForIp(inputVal);
1101 }
1102 if (this.maskExpression === "CPF_CNPJ" /* MaskExpression.CPF_CNPJ */) {
1103 return this._checkForCpfCnpj(inputVal);
1104 }
1105 }
1106 if (this.placeHolderCharacter.length === this.maskExpression.length) {
1107 return this.placeHolderCharacter;
1108 }
1109 return this.maskExpression.replace(/\w/g, this.placeHolderCharacter);
1110 }
1111 return '';
1112 }
1113 clearIfNotMatchFn() {
1114 const formElement = this._elementRef?.nativeElement;
1115 if (!formElement) {
1116 return;
1117 }
1118 if (this.clearIfNotMatch &&
1119 this.prefix.length + this.maskExpression.length + this.suffix.length !==
1120 formElement.value.replace(this.placeHolderCharacter, "" /* MaskExpression.EMPTY_STRING */)
1121 .length) {
1122 this.formElementProperty = ['value', "" /* MaskExpression.EMPTY_STRING */];
1123 this.applyMask('', this.maskExpression);
1124 }
1125 }
1126 set formElementProperty([name, value]) {
1127 if (!this._renderer || !this._elementRef) {
1128 return;
1129 }
1130 //[TODO]: andriikamaldinov1 find better solution
1131 Promise.resolve().then(() => this._renderer?.setProperty(this._elementRef?.nativeElement, name, value));
1132 }
1133 checkDropSpecialCharAmount(mask) {
1134 const chars = mask
1135 .split("" /* MaskExpression.EMPTY_STRING */)
1136 .filter((item) => this._findDropSpecialChar(item));
1137 return chars.length;
1138 }
1139 removeMask(inputValue) {
1140 return this._removeMask(this._removeSuffix(this._removePrefix(inputValue)), this.specialCharacters.concat('_').concat(this.placeHolderCharacter));
1141 }
1142 _checkForIp(inputVal) {
1143 if (inputVal === "#" /* MaskExpression.HASH */) {
1144 return `${this.placeHolderCharacter}.${this.placeHolderCharacter}.${this.placeHolderCharacter}.${this.placeHolderCharacter}`;
1145 }
1146 const arr = [];
1147 for (let i = 0; i < inputVal.length; i++) {
1148 const value = inputVal[i] ?? "" /* MaskExpression.EMPTY_STRING */;
1149 if (!value) {
1150 continue;
1151 }
1152 if (value.match('\\d')) {
1153 arr.push(value);
1154 }
1155 }
1156 if (arr.length <= 3) {
1157 return `${this.placeHolderCharacter}.${this.placeHolderCharacter}.${this.placeHolderCharacter}`;
1158 }
1159 if (arr.length > 3 && arr.length <= 6) {
1160 return `${this.placeHolderCharacter}.${this.placeHolderCharacter}`;
1161 }
1162 if (arr.length > 6 && arr.length <= 9) {
1163 return this.placeHolderCharacter;
1164 }
1165 if (arr.length > 9 && arr.length <= 12) {
1166 return '';
1167 }
1168 return '';
1169 }
1170 _checkForCpfCnpj(inputVal) {
1171 const cpf = `${this.placeHolderCharacter}${this.placeHolderCharacter}${this.placeHolderCharacter}` +
1172 `.${this.placeHolderCharacter}${this.placeHolderCharacter}${this.placeHolderCharacter}` +
1173 `.${this.placeHolderCharacter}${this.placeHolderCharacter}${this.placeHolderCharacter}` +
1174 `-${this.placeHolderCharacter}${this.placeHolderCharacter}`;
1175 const cnpj = `${this.placeHolderCharacter}${this.placeHolderCharacter}` +
1176 `.${this.placeHolderCharacter}${this.placeHolderCharacter}${this.placeHolderCharacter}` +
1177 `.${this.placeHolderCharacter}${this.placeHolderCharacter}${this.placeHolderCharacter}` +
1178 `/${this.placeHolderCharacter}${this.placeHolderCharacter}${this.placeHolderCharacter}${this.placeHolderCharacter}` +
1179 `-${this.placeHolderCharacter}${this.placeHolderCharacter}`;
1180 if (inputVal === "#" /* MaskExpression.HASH */) {
1181 return cpf;
1182 }
1183 const arr = [];
1184 for (let i = 0; i < inputVal.length; i++) {
1185 const value = inputVal[i] ?? "" /* MaskExpression.EMPTY_STRING */;
1186 if (!value) {
1187 continue;
1188 }
1189 if (value.match('\\d')) {
1190 arr.push(value);
1191 }
1192 }
1193 if (arr.length <= 3) {
1194 return cpf.slice(arr.length, cpf.length);
1195 }
1196 if (arr.length > 3 && arr.length <= 6) {
1197 return cpf.slice(arr.length + 1, cpf.length);
1198 }
1199 if (arr.length > 6 && arr.length <= 9) {
1200 return cpf.slice(arr.length + 2, cpf.length);
1201 }
1202 if (arr.length > 9 && arr.length < 11) {
1203 return cpf.slice(arr.length + 3, cpf.length);
1204 }
1205 if (arr.length === 11) {
1206 return '';
1207 }
1208 if (arr.length === 12) {
1209 if (inputVal.length === 17) {
1210 return cnpj.slice(16, cnpj.length);
1211 }
1212 return cnpj.slice(15, cnpj.length);
1213 }
1214 if (arr.length > 12 && arr.length <= 14) {
1215 return cnpj.slice(arr.length + 4, cnpj.length);
1216 }
1217 return '';
1218 }
1219 /**
1220 * Recursively determine the current active element by navigating the Shadow DOM until the Active Element is found.
1221 */
1222 _getActiveElement(document = this.document) {
1223 const shadowRootEl = document?.activeElement?.shadowRoot;
1224 if (!shadowRootEl?.activeElement) {
1225 return document.activeElement;
1226 }
1227 else {
1228 return this._getActiveElement(shadowRootEl);
1229 }
1230 }
1231 /**
1232 * Propogates the input value back to the Angular model by triggering the onChange function. It won't do this if writingValue
1233 * is true. If that is true it means we are currently in the writeValue function, which is supposed to only update the actual
1234 * DOM element based on the Angular model value. It should be a one way process, i.e. writeValue should not be modifying the Angular
1235 * model value too. Therefore, we don't trigger onChange in this scenario.
1236 * @param inputValue the current form input value
1237 */
1238 formControlResult(inputValue) {
1239 if (this.writingValue || (!this.triggerOnMaskChange && this.maskChanged)) {
1240 this.triggerOnMaskChange && this.maskChanged
1241 ? this.onChange(this.outputTransformFn(this._toNumber(this._checkSymbols(this._removeSuffix(this._removePrefix(inputValue))))))
1242 : '';
1243 this.maskChanged = false;
1244 return;
1245 }
1246 if (Array.isArray(this.dropSpecialCharacters)) {
1247 this.onChange(this.outputTransformFn(this._toNumber(this._checkSymbols(this._removeMask(this._removeSuffix(this._removePrefix(inputValue)), this.dropSpecialCharacters)))));
1248 }
1249 else if (this.dropSpecialCharacters ||
1250 (!this.dropSpecialCharacters && this.prefix === inputValue)) {
1251 this.onChange(this.outputTransformFn(this._toNumber(this._checkSymbols(this._removeSuffix(this._removePrefix(inputValue))))));
1252 }
1253 else {
1254 this.onChange(this.outputTransformFn(this._toNumber(inputValue)));
1255 }
1256 }
1257 _toNumber(value) {
1258 if (!this.isNumberValue || value === "" /* MaskExpression.EMPTY_STRING */) {
1259 return value;
1260 }
1261 if (this.maskExpression.startsWith("separator" /* MaskExpression.SEPARATOR */) &&
1262 (this.leadZero || !this.dropSpecialCharacters)) {
1263 return value;
1264 }
1265 if (String(value).length > 16 && this.separatorLimit.length > 14) {
1266 return String(value);
1267 }
1268 const num = Number(value);
1269 if (this.maskExpression.startsWith("separator" /* MaskExpression.SEPARATOR */) && Number.isNaN(num)) {
1270 const val = String(value).replace(',', '.');
1271 return Number(val);
1272 }
1273 return Number.isNaN(num) ? value : num;
1274 }
1275 _removeMask(value, specialCharactersForRemove) {
1276 if (this.maskExpression.startsWith("percent" /* MaskExpression.PERCENT */) &&
1277 value.includes("." /* MaskExpression.DOT */)) {
1278 return value;
1279 }
1280 return value
1281 ? value.replace(this._regExpForRemove(specialCharactersForRemove), "" /* MaskExpression.EMPTY_STRING */)
1282 : value;
1283 }
1284 _removePrefix(value) {
1285 if (!this.prefix) {
1286 return value;
1287 }
1288 return value ? value.replace(this.prefix, "" /* MaskExpression.EMPTY_STRING */) : value;
1289 }
1290 _removeSuffix(value) {
1291 if (!this.suffix) {
1292 return value;
1293 }
1294 return value ? value.replace(this.suffix, "" /* MaskExpression.EMPTY_STRING */) : value;
1295 }
1296 _retrieveSeparatorValue(result) {
1297 let specialCharacters = Array.isArray(this.dropSpecialCharacters)
1298 ? this.specialCharacters.filter((v) => {
1299 return this.dropSpecialCharacters.includes(v);
1300 })
1301 : this.specialCharacters;
1302 if (!this.deletedSpecialCharacter &&
1303 this._checkPatternForSpace() &&
1304 result.includes(" " /* MaskExpression.WHITE_SPACE */) &&
1305 this.maskExpression.includes("*" /* MaskExpression.SYMBOL_STAR */)) {
1306 specialCharacters = specialCharacters.filter((char) => char !== " " /* MaskExpression.WHITE_SPACE */);
1307 }
1308 return this._removeMask(result, specialCharacters);
1309 }
1310 _regExpForRemove(specialCharactersForRemove) {
1311 return new RegExp(specialCharactersForRemove.map((item) => `\\${item}`).join('|'), 'gi');
1312 }
1313 _replaceDecimalMarkerToDot(value) {
1314 const markers = Array.isArray(this.decimalMarker)
1315 ? this.decimalMarker
1316 : [this.decimalMarker];
1317 return value.replace(this._regExpForRemove(markers), "." /* MaskExpression.DOT */);
1318 }
1319 _checkSymbols(result) {
1320 if (result === "" /* MaskExpression.EMPTY_STRING */) {
1321 return result;
1322 }
1323 if (this.maskExpression.startsWith("percent" /* MaskExpression.PERCENT */) &&
1324 this.decimalMarker === "," /* MaskExpression.COMMA */) {
1325 result = result.replace("," /* MaskExpression.COMMA */, "." /* MaskExpression.DOT */);
1326 }
1327 const separatorPrecision = this._retrieveSeparatorPrecision(this.maskExpression);
1328 const separatorValue = this._replaceDecimalMarkerToDot(this._retrieveSeparatorValue(result));
1329 if (!this.isNumberValue) {
1330 return separatorValue;
1331 }
1332 if (separatorPrecision) {
1333 if (result === this.decimalMarker) {
1334 return null;
1335 }
1336 if (this.separatorLimit.length > 14) {
1337 return String(separatorValue);
1338 }
1339 return this._checkPrecision(this.maskExpression, separatorValue);
1340 }
1341 else {
1342 return separatorValue;
1343 }
1344 }
1345 _checkPatternForSpace() {
1346 for (const key in this.patterns) {
1347 // eslint-disable-next-line no-prototype-builtins
1348 if (this.patterns[key] && this.patterns[key]?.hasOwnProperty('pattern')) {
1349 const patternString = this.patterns[key]?.pattern.toString();
1350 const pattern = this.patterns[key]?.pattern;
1351 if (patternString?.includes(" " /* MaskExpression.WHITE_SPACE */) &&
1352 pattern?.test(this.maskExpression)) {
1353 return true;
1354 }
1355 }
1356 }
1357 return false;
1358 }
1359 // TODO should think about helpers or separting decimal precision to own property
1360 _retrieveSeparatorPrecision(maskExpretion) {
1361 const matcher = maskExpretion.match(new RegExp(`^separator\\.([^d]*)`));
1362 return matcher ? Number(matcher[1]) : null;
1363 }
1364 _checkPrecision(separatorExpression, separatorValue) {
1365 const separatorPrecision = separatorExpression.slice(10, 11);
1366 if (separatorExpression.indexOf('2') > 0 ||
1367 (this.leadZero && Number(separatorPrecision) > 0)) {
1368 if (this.decimalMarker === "," /* MaskExpression.COMMA */ && this.leadZero) {
1369 separatorValue = separatorValue.replace(',', '.');
1370 }
1371 return this.leadZero
1372 ? Number(separatorValue).toFixed(Number(separatorPrecision))
1373 : Number(separatorValue).toFixed(2);
1374 }
1375 return this.numberToString(separatorValue);
1376 }
1377 _repeatPatternSymbols(maskExp) {
1378 return ((maskExp.match(/{[0-9]+}/) &&
1379 maskExp
1380 .split("" /* MaskExpression.EMPTY_STRING */)
1381 .reduce((accum, currVal, index) => {
1382 this._start =
1383 currVal === "{" /* MaskExpression.CURLY_BRACKETS_LEFT */ ? index : this._start;
1384 if (currVal !== "}" /* MaskExpression.CURLY_BRACKETS_RIGHT */) {
1385 return this._findSpecialChar(currVal) ? accum + currVal : accum;
1386 }
1387 this._end = index;
1388 const repeatNumber = Number(maskExp.slice(this._start + 1, this._end));
1389 const replaceWith = new Array(repeatNumber + 1).join(maskExp[this._start - 1]);
1390 if (maskExp.slice(0, this._start).length > 1 &&
1391 maskExp.includes("S" /* MaskExpression.LETTER_S */)) {
1392 const symbols = maskExp.slice(0, this._start - 1);
1393 return symbols.includes("{" /* MaskExpression.CURLY_BRACKETS_LEFT */)
1394 ? accum + replaceWith
1395 : symbols + accum + replaceWith;
1396 }
1397 else {
1398 return accum + replaceWith;
1399 }
1400 }, '')) ||
1401 maskExp);
1402 }
1403 currentLocaleDecimalMarker() {
1404 return (1.1).toLocaleString().substring(1, 2);
1405 }
1406 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.1", ngImport: i0, type: NgxMaskService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
1407 static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.1.1", ngImport: i0, type: NgxMaskService }); }
1408}
1409i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.1", ngImport: i0, type: NgxMaskService, decorators: [{
1410 type: Injectable
1411 }] });
1412
1413/**
1414 * @internal
1415 */
1416function _configFactory() {
1417 const initConfig = inject(INITIAL_CONFIG);
1418 const configValue = inject(NEW_CONFIG);
1419 return configValue instanceof Function
1420 ? { ...initConfig, ...configValue() }
1421 : { ...initConfig, ...configValue };
1422}
1423function provideNgxMask(configValue) {
1424 return [
1425 {
1426 provide: NEW_CONFIG,
1427 useValue: configValue,
1428 },
1429 {
1430 provide: INITIAL_CONFIG,
1431 useValue: initialConfig,
1432 },
1433 {
1434 provide: NGX_MASK_CONFIG,
1435 useFactory: _configFactory,
1436 },
1437 NgxMaskService,
1438 ];
1439}
1440function provideEnvironmentNgxMask(configValue) {
1441 return makeEnvironmentProviders(provideNgxMask(configValue));
1442}
1443
1444class NgxMaskDirective {
1445 constructor() {
1446 this.maskExpression = '';
1447 this.specialCharacters = [];
1448 this.patterns = {};
1449 this.prefix = '';
1450 this.suffix = '';
1451 this.thousandSeparator = ' ';
1452 this.decimalMarker = '.';
1453 this.dropSpecialCharacters = null;
1454 this.hiddenInput = null;
1455 this.showMaskTyped = null;
1456 this.placeHolderCharacter = null;
1457 this.shownMaskExpression = null;
1458 this.showTemplate = null;
1459 this.clearIfNotMatch = null;
1460 this.validation = null;
1461 this.separatorLimit = null;
1462 this.allowNegativeNumbers = null;
1463 this.leadZeroDateTime = null;
1464 this.leadZero = null;
1465 this.triggerOnMaskChange = null;
1466 this.apm = null;
1467 this.inputTransformFn = null;
1468 this.outputTransformFn = null;
1469 this.keepCharacterPositions = null;
1470 this.maskFilled = new EventEmitter();
1471 this._maskValue = '';
1472 this._position = null;
1473 this._maskExpressionArray = [];
1474 this._allowFewMaskChangeMask = false;
1475 this._justPasted = false;
1476 this._isFocused = false;
1477 /**For IME composition event */
1478 this._isComposing = false;
1479 this.document = inject(DOCUMENT);
1480 this._maskService = inject(NgxMaskService, { self: true });
1481 this._config = inject(NGX_MASK_CONFIG);
1482 // eslint-disable-next-line @typescript-eslint/no-explicit-any
1483 this.onChange = (_) => { };
1484 this.onTouch = () => { };
1485 }
1486 ngOnChanges(changes) {
1487 const { maskExpression, specialCharacters, patterns, prefix, suffix, thousandSeparator, decimalMarker, dropSpecialCharacters, hiddenInput, showMaskTyped, placeHolderCharacter, shownMaskExpression, showTemplate, clearIfNotMatch, validation, separatorLimit, allowNegativeNumbers, leadZeroDateTime, leadZero, triggerOnMaskChange, apm, inputTransformFn, outputTransformFn, keepCharacterPositions, } = changes;
1488 if (maskExpression) {
1489 if (maskExpression.currentValue !== maskExpression.previousValue &&
1490 !maskExpression.firstChange) {
1491 this._maskService.maskChanged = true;
1492 }
1493 if (maskExpression.currentValue &&
1494 maskExpression.currentValue.split("||" /* MaskExpression.OR */).length > 1) {
1495 this._maskExpressionArray = maskExpression.currentValue
1496 .split("||" /* MaskExpression.OR */)
1497 .sort((a, b) => {
1498 return a.length - b.length;
1499 });
1500 this._setMask();
1501 }
1502 else {
1503 this._maskExpressionArray = [];
1504 this._maskValue = maskExpression.currentValue || "" /* MaskExpression.EMPTY_STRING */;
1505 this._maskService.maskExpression = this._maskValue;
1506 }
1507 }
1508 if (specialCharacters) {
1509 if (!specialCharacters.currentValue || !Array.isArray(specialCharacters.currentValue)) {
1510 return;
1511 }
1512 else {
1513 this._maskService.specialCharacters = specialCharacters.currentValue || [];
1514 }
1515 }
1516 if (allowNegativeNumbers) {
1517 this._maskService.allowNegativeNumbers = allowNegativeNumbers.currentValue;
1518 if (this._maskService.allowNegativeNumbers) {
1519 this._maskService.specialCharacters = this._maskService.specialCharacters.filter((c) => c !== "-" /* MaskExpression.MINUS */);
1520 }
1521 }
1522 // Only overwrite the mask available patterns if a pattern has actually been passed in
1523 if (patterns && patterns.currentValue) {
1524 this._maskService.patterns = patterns.currentValue;
1525 }
1526 if (apm && apm.currentValue) {
1527 this._maskService.apm = apm.currentValue;
1528 }
1529 if (prefix) {
1530 this._maskService.prefix = prefix.currentValue;
1531 }
1532 if (suffix) {
1533 this._maskService.suffix = suffix.currentValue;
1534 }
1535 if (thousandSeparator) {
1536 this._maskService.thousandSeparator = thousandSeparator.currentValue;
1537 }
1538 if (decimalMarker) {
1539 this._maskService.decimalMarker = decimalMarker.currentValue;
1540 }
1541 if (dropSpecialCharacters) {
1542 this._maskService.dropSpecialCharacters = dropSpecialCharacters.currentValue;
1543 }
1544 if (hiddenInput) {
1545 this._maskService.hiddenInput = hiddenInput.currentValue;
1546 }
1547 if (showMaskTyped) {
1548 this._maskService.showMaskTyped = showMaskTyped.currentValue;
1549 if (showMaskTyped.previousValue === false &&
1550 showMaskTyped.currentValue === true &&
1551 this._isFocused) {
1552 requestAnimationFrame(() => {
1553 this._maskService._elementRef?.nativeElement.click();
1554 });
1555 }
1556 }
1557 if (placeHolderCharacter) {
1558 this._maskService.placeHolderCharacter = placeHolderCharacter.currentValue;
1559 }
1560 if (shownMaskExpression) {
1561 this._maskService.shownMaskExpression = shownMaskExpression.currentValue;
1562 }
1563 if (showTemplate) {
1564 this._maskService.showTemplate = showTemplate.currentValue;
1565 }
1566 if (clearIfNotMatch) {
1567 this._maskService.clearIfNotMatch = clearIfNotMatch.currentValue;
1568 }
1569 if (validation) {
1570 this._maskService.validation = validation.currentValue;
1571 }
1572 if (separatorLimit) {
1573 this._maskService.separatorLimit = separatorLimit.currentValue;
1574 }
1575 if (leadZeroDateTime) {
1576 this._maskService.leadZeroDateTime = leadZeroDateTime.currentValue;
1577 }
1578 if (leadZero) {
1579 this._maskService.leadZero = leadZero.currentValue;
1580 }
1581 if (triggerOnMaskChange) {
1582 this._maskService.triggerOnMaskChange = triggerOnMaskChange.currentValue;
1583 }
1584 if (inputTransformFn) {
1585 this._maskService.inputTransformFn = inputTransformFn.currentValue;
1586 }
1587 if (outputTransformFn) {
1588 this._maskService.outputTransformFn = outputTransformFn.currentValue;
1589 }
1590 if (keepCharacterPositions) {
1591 this._maskService.keepCharacterPositions = keepCharacterPositions.currentValue;
1592 }
1593 this._applyMask();
1594 }
1595 validate({ value }) {
1596 if (!this._maskService.validation || !this._maskValue) {
1597 return null;
1598 }
1599 if (this._maskService.ipError) {
1600 return this._createValidationError(value);
1601 }
1602 if (this._maskService.cpfCnpjError) {
1603 return this._createValidationError(value);
1604 }
1605 if (this._maskValue.startsWith("separator" /* MaskExpression.SEPARATOR */)) {
1606 return null;
1607 }
1608 if (withoutValidation.includes(this._maskValue)) {
1609 return null;
1610 }
1611 if (this._maskService.clearIfNotMatch) {
1612 return null;
1613 }
1614 if (timeMasks.includes(this._maskValue)) {
1615 return this._validateTime(value);
1616 }
1617 if (value && value.toString().length >= 1) {
1618 let counterOfOpt = 0;
1619 if (this._maskValue.includes("{" /* MaskExpression.CURLY_BRACKETS_LEFT */) &&
1620 this._maskValue.includes("}" /* MaskExpression.CURLY_BRACKETS_RIGHT */)) {
1621 const lengthInsideCurlyBrackets = this._maskValue.slice(this._maskValue.indexOf("{" /* MaskExpression.CURLY_BRACKETS_LEFT */) + 1, this._maskValue.indexOf("}" /* MaskExpression.CURLY_BRACKETS_RIGHT */));
1622 return lengthInsideCurlyBrackets === String(value.length)
1623 ? null
1624 : this._createValidationError(value);
1625 }
1626 if (this._maskValue.startsWith("percent" /* MaskExpression.PERCENT */)) {
1627 return null;
1628 }
1629 for (const key in this._maskService.patterns) {
1630 if (this._maskService.patterns[key]?.optional) {
1631 if (this._maskValue.indexOf(key) !== this._maskValue.lastIndexOf(key)) {
1632 const opt = this._maskValue
1633 .split("" /* MaskExpression.EMPTY_STRING */)
1634 .filter((i) => i === key)
1635 .join("" /* MaskExpression.EMPTY_STRING */);
1636 counterOfOpt += opt.length;
1637 }
1638 else if (this._maskValue.indexOf(key) !== -1) {
1639 counterOfOpt++;
1640 }
1641 if (this._maskValue.indexOf(key) !== -1 &&
1642 value.toString().length >= this._maskValue.indexOf(key)) {
1643 return null;
1644 }
1645 if (counterOfOpt === this._maskValue.length) {
1646 return null;
1647 }
1648 }
1649 }
1650 if ((this._maskValue.indexOf("*" /* MaskExpression.SYMBOL_STAR */) > 1 &&
1651 value.toString().length <
1652 this._maskValue.indexOf("*" /* MaskExpression.SYMBOL_STAR */)) ||
1653 (this._maskValue.indexOf("?" /* MaskExpression.SYMBOL_QUESTION */) > 1 &&
1654 value.toString().length <
1655 this._maskValue.indexOf("?" /* MaskExpression.SYMBOL_QUESTION */))) {
1656 return this._createValidationError(value);
1657 }
1658 if (this._maskValue.indexOf("*" /* MaskExpression.SYMBOL_STAR */) === -1 ||
1659 this._maskValue.indexOf("?" /* MaskExpression.SYMBOL_QUESTION */) === -1) {
1660 value = typeof value === 'number' ? String(value) : value;
1661 const array = this._maskValue.split('*');
1662 const length = this._maskService.dropSpecialCharacters
1663 ? this._maskValue.length -
1664 this._maskService.checkDropSpecialCharAmount(this._maskValue) -
1665 counterOfOpt
1666 : this.prefix
1667 ? this._maskValue.length + this.prefix.length - counterOfOpt
1668 : this._maskValue.length - counterOfOpt;
1669 if (array.length === 1) {
1670 if (value.toString().length < length) {
1671 return this._createValidationError(value);
1672 }
1673 }
1674 if (array.length > 1) {
1675 const lastIndexArray = array[array.length - 1];
1676 if (lastIndexArray &&
1677 this._maskService.specialCharacters.includes(lastIndexArray[0]) &&
1678 String(value).includes(lastIndexArray[0] ?? '') &&
1679 !this.dropSpecialCharacters) {
1680 const special = value.split(lastIndexArray[0]);
1681 return special[special.length - 1].length === lastIndexArray.length - 1
1682 ? null
1683 : this._createValidationError(value);
1684 }
1685 else if (((lastIndexArray &&
1686 !this._maskService.specialCharacters.includes(lastIndexArray[0])) ||
1687 !lastIndexArray ||
1688 this._maskService.dropSpecialCharacters) &&
1689 value.length >= length - 1) {
1690 return null;
1691 }
1692 else {
1693 return this._createValidationError(value);
1694 }
1695 }
1696 }
1697 if (this._maskValue.indexOf("*" /* MaskExpression.SYMBOL_STAR */) === 1 ||
1698 this._maskValue.indexOf("?" /* MaskExpression.SYMBOL_QUESTION */) === 1) {
1699 return null;
1700 }
1701 }
1702 if (value) {
1703 this.maskFilled.emit();
1704 return null;
1705 }
1706 return null;
1707 }
1708 onPaste() {
1709 this._justPasted = true;
1710 }
1711 onFocus() {
1712 this._isFocused = true;
1713 }
1714 onModelChange(value) {
1715 // on form reset we need to update the actualValue
1716 if ((value === "" /* MaskExpression.EMPTY_STRING */ || value === null || value === undefined) &&
1717 this._maskService.actualValue) {
1718 this._maskService.actualValue = this._maskService.getActualValue("" /* MaskExpression.EMPTY_STRING */);
1719 }
1720 }
1721 onInput(e) {
1722 // If IME is composing text, we wait for the composed text.
1723 if (this._isComposing)
1724 return;
1725 const el = e.target;
1726 const transformedValue = this._maskService.inputTransformFn(el.value);
1727 if (el.type !== 'number') {
1728 if (typeof transformedValue === 'string' || typeof transformedValue === 'number') {
1729 el.value = transformedValue.toString();
1730 this._inputValue = el.value;
1731 this._setMask();
1732 if (!this._maskValue) {
1733 this.onChange(el.value);
1734 return;
1735 }
1736 let position = el.selectionStart === 1
1737 ? el.selectionStart + this._maskService.prefix.length
1738 : el.selectionStart;
1739 if (this.showMaskTyped &&
1740 this.keepCharacterPositions &&
1741 this._maskService.placeHolderCharacter.length === 1) {
1742 const inputSymbol = el.value.slice(position - 1, position);
1743 const prefixLength = this.prefix.length;
1744 const checkSymbols = this._maskService._checkSymbolMask(inputSymbol, this._maskService.maskExpression[position - 1 - prefixLength] ??
1745 "" /* MaskExpression.EMPTY_STRING */);
1746 const checkSpecialCharacter = this._maskService._checkSymbolMask(inputSymbol, this._maskService.maskExpression[position + 1 - prefixLength] ??
1747 "" /* MaskExpression.EMPTY_STRING */);
1748 const selectRangeBackspace = this._maskService.selStart === this._maskService.selEnd;
1749 const selStart = Number(this._maskService.selStart) - prefixLength;
1750 const selEnd = Number(this._maskService.selEnd) - prefixLength;
1751 if (this._code === "Backspace" /* MaskExpression.BACKSPACE */) {
1752 if (!selectRangeBackspace) {
1753 if (this._maskService.selStart === prefixLength) {
1754 this._maskService.actualValue = `${this.prefix}${this._maskService.maskIsShown.slice(0, selEnd)}${this._inputValue.split(this.prefix).join('')}`;
1755 }
1756 else if (this._maskService.selStart ===
1757 this._maskService.maskIsShown.length + prefixLength) {
1758 this._maskService.actualValue = `${this._inputValue}${this._maskService.maskIsShown.slice(selStart, selEnd)}`;
1759 }
1760 else {
1761 this._maskService.actualValue = `${this.prefix}${this._inputValue
1762 .split(this.prefix)
1763 .join('')
1764 .slice(0, selStart)}${this._maskService.maskIsShown.slice(selStart, selEnd)}${this._maskService.actualValue.slice(selEnd + prefixLength, this._maskService.maskIsShown.length + prefixLength)}${this.suffix}`;
1765 }
1766 }
1767 else if (!this._maskService.specialCharacters.includes(this._maskService.maskExpression.slice(position - this.prefix.length, position + 1 - this.prefix.length)) &&
1768 selectRangeBackspace) {
1769 if (selStart === 1 && this.prefix) {
1770 this._maskService.actualValue = `${this.prefix}${this._maskService.placeHolderCharacter}${el.value
1771 .split(this.prefix)
1772 .join('')
1773 .split(this.suffix)
1774 .join('')}${this.suffix}`;
1775 position = position - 1;
1776 }
1777 else {
1778 const part1 = el.value.substring(0, position);
1779 const part2 = el.value.substring(position);
1780 this._maskService.actualValue = `${part1}${this._maskService.placeHolderCharacter}${part2}`;
1781 }
1782 }
1783 }
1784 if (this._code !== "Backspace" /* MaskExpression.BACKSPACE */) {
1785 if (!checkSymbols && !checkSpecialCharacter && selectRangeBackspace) {
1786 position = Number(el.selectionStart) - 1;
1787 }
1788 else if (this._maskService.specialCharacters.includes(el.value.slice(position, position + 1)) &&
1789 checkSpecialCharacter &&
1790 !this._maskService.specialCharacters.includes(el.value.slice(position + 1, position + 2))) {
1791 this._maskService.actualValue = `${el.value.slice(0, position - 1)}${el.value.slice(position, position + 1)}${inputSymbol}${el.value.slice(position + 2)}`;
1792 position = position + 1;
1793 }
1794 else if (checkSymbols) {
1795 if (el.value.length === 1 && position === 1) {
1796 this._maskService.actualValue = `${this.prefix}${inputSymbol}${this._maskService.maskIsShown.slice(1, this._maskService.maskIsShown.length)}${this.suffix}`;
1797 }
1798 else {
1799 this._maskService.actualValue = `${el.value.slice(0, position - 1)}${inputSymbol}${el.value
1800 .slice(position + 1)
1801 .split(this.suffix)
1802 .join('')}${this.suffix}`;
1803 }
1804 }
1805 else if (this.prefix &&
1806 el.value.length === 1 &&
1807 position - prefixLength === 1 &&
1808 this._maskService._checkSymbolMask(el.value, this._maskService.maskExpression[position - 1 - prefixLength] ??
1809 "" /* MaskExpression.EMPTY_STRING */)) {
1810 this._maskService.actualValue = `${this.prefix}${el.value}${this._maskService.maskIsShown.slice(1, this._maskService.maskIsShown.length)}${this.suffix}`;
1811 }
1812 }
1813 }
1814 let caretShift = 0;
1815 let backspaceShift = false;
1816 if (this._code === "Delete" /* MaskExpression.DELETE */ && "separator" /* MaskExpression.SEPARATOR */) {
1817 this._maskService.deletedSpecialCharacter = true;
1818 }
1819 if (this._inputValue.length >= this._maskService.maskExpression.length - 1 &&
1820 this._code !== "Backspace" /* MaskExpression.BACKSPACE */ &&
1821 this._maskService.maskExpression === "d0/M0/0000" /* MaskExpression.DAYS_MONTHS_YEARS */ &&
1822 position < 10) {
1823 const inputSymbol = this._inputValue.slice(position - 1, position);
1824 el.value =
1825 this._inputValue.slice(0, position - 1) +
1826 inputSymbol +
1827 this._inputValue.slice(position + 1);
1828 }
1829 if (this._maskService.maskExpression === "d0/M0/0000" /* MaskExpression.DAYS_MONTHS_YEARS */ &&
1830 this.leadZeroDateTime) {
1831 if ((position < 3 && Number(el.value) > 31 && Number(el.value) < 40) ||
1832 (position === 5 && Number(el.value.slice(3, 5)) > 12)) {
1833 position = position + 2;
1834 }
1835 }
1836 if (this._maskService.maskExpression === "Hh:m0:s0" /* MaskExpression.HOURS_MINUTES_SECONDS */ &&
1837 this.apm) {
1838 if (this._justPasted && el.value.slice(0, 2) === "00" /* MaskExpression.DOUBLE_ZERO */) {
1839 el.value = el.value.slice(1, 2) + el.value.slice(2, el.value.length);
1840 }
1841 el.value =
1842 el.value === "00" /* MaskExpression.DOUBLE_ZERO */
1843 ? "0" /* MaskExpression.NUMBER_ZERO */
1844 : el.value;
1845 }
1846 this._maskService.applyValueChanges(position, this._justPasted, this._code === "Backspace" /* MaskExpression.BACKSPACE */ || this._code === "Delete" /* MaskExpression.DELETE */, (shift, _backspaceShift) => {
1847 this._justPasted = false;
1848 caretShift = shift;
1849 backspaceShift = _backspaceShift;
1850 });
1851 // only set the selection if the element is active
1852 if (this._getActiveElement() !== el) {
1853 return;
1854 }
1855 if (this._maskService.plusOnePosition) {
1856 position = position + 1;
1857 this._maskService.plusOnePosition = false;
1858 }
1859 // update position after applyValueChanges to prevent cursor on wrong position when it has an array of maskExpression
1860 if (this._maskExpressionArray.length) {
1861 if (this._code === "Backspace" /* MaskExpression.BACKSPACE */) {
1862 const specialChartMinusOne = this.specialCharacters.includes(this._maskService.actualValue.slice(position - 1, position));
1863 const specialChartPlusOne = this.specialCharacters.includes(this._maskService.actualValue.slice(position, position + 1));
1864 if (this._allowFewMaskChangeMask && !specialChartPlusOne) {
1865 position = el.selectionStart + 1;
1866 this._allowFewMaskChangeMask = false;
1867 }
1868 else {
1869 position = specialChartMinusOne ? position - 1 : position;
1870 }
1871 }
1872 else {
1873 position =
1874 el.selectionStart === 1
1875 ? el.selectionStart + this._maskService.prefix.length
1876 : el.selectionStart;
1877 }
1878 }
1879 this._position =
1880 this._position === 1 && this._inputValue.length === 1 ? null : this._position;
1881 let positionToApply = this._position
1882 ? this._inputValue.length + position + caretShift
1883 : position +
1884 (this._code === "Backspace" /* MaskExpression.BACKSPACE */ && !backspaceShift ? 0 : caretShift);
1885 if (positionToApply > this._getActualInputLength()) {
1886 positionToApply =
1887 el.value === this._maskService.decimalMarker && el.value.length === 1
1888 ? this._getActualInputLength() + 1
1889 : this._getActualInputLength();
1890 }
1891 if (positionToApply < 0) {
1892 positionToApply = 0;
1893 }
1894 el.setSelectionRange(positionToApply, positionToApply);
1895 this._position = null;
1896 }
1897 else {
1898 console.warn('Ngx-mask writeValue work with string | number, your current value:', typeof transformedValue);
1899 }
1900 }
1901 else {
1902 if (!this._maskValue) {
1903 this.onChange(el.value);
1904 return;
1905 }
1906 this._maskService.applyValueChanges(el.value.length, this._justPasted, this._code === "Backspace" /* MaskExpression.BACKSPACE */ || this._code === "Delete" /* MaskExpression.DELETE */);
1907 }
1908 }
1909 // IME starts
1910 onCompositionStart() {
1911 this._isComposing = true;
1912 }
1913 // IME completes
1914 onCompositionEnd(e) {
1915 this._isComposing = false;
1916 this._justPasted = true;
1917 this.onInput(e);
1918 }
1919 onBlur(e) {
1920 if (this._maskValue) {
1921 const el = e.target;
1922 if (this.leadZero && el.value.length > 0 && typeof this.decimalMarker === 'string') {
1923 const maskExpression = this._maskService.maskExpression;
1924 const precision = Number(this._maskService.maskExpression.slice(maskExpression.length - 1, maskExpression.length));
1925 if (precision > 0) {
1926 el.value = this.suffix ? el.value.split(this.suffix).join('') : el.value;
1927 const decimalPart = el.value.split(this.decimalMarker)[1];
1928 el.value = el.value.includes(this.decimalMarker)
1929 ? el.value +
1930 "0" /* MaskExpression.NUMBER_ZERO */.repeat(precision - decimalPart.length) +
1931 this.suffix
1932 : el.value +
1933 this.decimalMarker +
1934 "0" /* MaskExpression.NUMBER_ZERO */.repeat(precision) +
1935 this.suffix;
1936 this._maskService.actualValue = el.value;
1937 }
1938 }
1939 this._maskService.clearIfNotMatchFn();
1940 }
1941 this._isFocused = false;
1942 this.onTouch();
1943 }
1944 onClick(e) {
1945 if (!this._maskValue) {
1946 return;
1947 }
1948 const el = e.target;
1949 const posStart = 0;
1950 const posEnd = 0;
1951 if (el !== null &&
1952 el.selectionStart !== null &&
1953 el.selectionStart === el.selectionEnd &&
1954 el.selectionStart > this._maskService.prefix.length &&
1955 // eslint-disable-next-line
1956 e.keyCode !== 38) {
1957 if (this._maskService.showMaskTyped && !this.keepCharacterPositions) {
1958 // We are showing the mask in the input
1959 this._maskService.maskIsShown = this._maskService.showMaskInInput();
1960 if (el.setSelectionRange &&
1961 this._maskService.prefix + this._maskService.maskIsShown === el.value) {
1962 // the input ONLY contains the mask, so position the cursor at the start
1963 el.focus();
1964 el.setSelectionRange(posStart, posEnd);
1965 }
1966 else {
1967 // the input contains some characters already
1968 if (el.selectionStart > this._maskService.actualValue.length) {
1969 // if the user clicked beyond our value's length, position the cursor at the end of our value
1970 el.setSelectionRange(this._maskService.actualValue.length, this._maskService.actualValue.length);
1971 }
1972 }
1973 }
1974 }
1975 const nextValue = el &&
1976 (el.value === this._maskService.prefix
1977 ? this._maskService.prefix + this._maskService.maskIsShown
1978 : el.value);
1979 /** Fix of cursor position jumping to end in most browsers no matter where cursor is inserted onFocus */
1980 if (el && el.value !== nextValue) {
1981 el.value = nextValue;
1982 }
1983 /** fix of cursor position with prefix when mouse click occur */
1984 if (el &&
1985 el.type !== 'number' &&
1986 (el.selectionStart || el.selectionEnd) <=
1987 this._maskService.prefix.length) {
1988 el.selectionStart = this._maskService.prefix.length;
1989 return;
1990 }
1991 /** select only inserted text */
1992 if (el && el.selectionEnd > this._getActualInputLength()) {
1993 el.selectionEnd = this._getActualInputLength();
1994 }
1995 }
1996 onKeyDown(e) {
1997 if (!this._maskValue) {
1998 return;
1999 }
2000 if (this._isComposing) {
2001 // User finalize their choice from IME composition, so trigger onInput() for the composed text.
2002 if (e.key === 'Enter')
2003 this.onCompositionEnd(e);
2004 return;
2005 }
2006 this._code = e.code ? e.code : e.key;
2007 const el = e.target;
2008 this._inputValue = el.value;
2009 this._setMask();
2010 if (el.type !== 'number') {
2011 if (e.key === "ArrowUp" /* MaskExpression.ARROW_UP */) {
2012 e.preventDefault();
2013 }
2014 if (e.key === "ArrowLeft" /* MaskExpression.ARROW_LEFT */ ||
2015 e.key === "Backspace" /* MaskExpression.BACKSPACE */ ||
2016 e.key === "Delete" /* MaskExpression.DELETE */) {
2017 if (e.key === "Backspace" /* MaskExpression.BACKSPACE */ && el.value.length === 0) {
2018 el.selectionStart = el.selectionEnd;
2019 }
2020 if (e.key === "Backspace" /* MaskExpression.BACKSPACE */ && el.selectionStart !== 0) {
2021 // If specialChars is false, (shouldn't ever happen) then set to the defaults
2022 this.specialCharacters = this.specialCharacters?.length
2023 ? this.specialCharacters
2024 : this._config.specialCharacters;
2025 if (this.prefix.length > 1 &&
2026 el.selectionStart <= this.prefix.length) {
2027 el.setSelectionRange(this.prefix.length, el.selectionEnd);
2028 }
2029 else {
2030 if (this._inputValue.length !== el.selectionStart &&
2031 el.selectionStart !== 1) {
2032 while (this.specialCharacters.includes((this._inputValue[el.selectionStart - 1] ??
2033 "" /* MaskExpression.EMPTY_STRING */).toString()) &&
2034 ((this.prefix.length >= 1 &&
2035 el.selectionStart > this.prefix.length) ||
2036 this.prefix.length === 0)) {
2037 el.setSelectionRange(el.selectionStart - 1, el.selectionEnd);
2038 }
2039 }
2040 }
2041 }
2042 this.checkSelectionOnDeletion(el);
2043 if (this._maskService.prefix.length &&
2044 el.selectionStart <= this._maskService.prefix.length &&
2045 el.selectionEnd <= this._maskService.prefix.length) {
2046 e.preventDefault();
2047 }
2048 const cursorStart = el.selectionStart;
2049 if (e.key === "Backspace" /* MaskExpression.BACKSPACE */ &&
2050 !el.readOnly &&
2051 cursorStart === 0 &&
2052 el.selectionEnd === el.value.length &&
2053 el.value.length !== 0) {
2054 this._position = this._maskService.prefix ? this._maskService.prefix.length : 0;
2055 this._maskService.applyMask(this._maskService.prefix, this._maskService.maskExpression, this._position);
2056 }
2057 }
2058 if (!!this.suffix &&
2059 this.suffix.length > 1 &&
2060 this._inputValue.length - this.suffix.length < el.selectionStart) {
2061 el.setSelectionRange(this._inputValue.length - this.suffix.length, this._inputValue.length);
2062 }
2063 else if ((e.code === 'KeyA' && e.ctrlKey) ||
2064 (e.code === 'KeyA' && e.metaKey) // Cmd + A (Mac)
2065 ) {
2066 el.setSelectionRange(0, this._getActualInputLength());
2067 e.preventDefault();
2068 }
2069 this._maskService.selStart = el.selectionStart;
2070 this._maskService.selEnd = el.selectionEnd;
2071 }
2072 }
2073 /** It writes the value in the input */
2074 async writeValue(controlValue) {
2075 if (typeof controlValue === 'object' && controlValue !== null && 'value' in controlValue) {
2076 if ('disable' in controlValue) {
2077 this.setDisabledState(Boolean(controlValue.disable));
2078 }
2079 controlValue = controlValue.value;
2080 }
2081 if (controlValue !== null) {
2082 controlValue = this.inputTransformFn
2083 ? this.inputTransformFn(controlValue)
2084 : controlValue;
2085 }
2086 if (typeof controlValue === 'string' ||
2087 typeof controlValue === 'number' ||
2088 controlValue === null ||
2089 controlValue === undefined) {
2090 if (controlValue === null || controlValue === undefined || controlValue === '') {
2091 this._maskService._currentValue = '';
2092 this._maskService._previousValue = '';
2093 }
2094 let inputValue = controlValue;
2095 if (typeof inputValue === 'number' ||
2096 this._maskValue.startsWith("separator" /* MaskExpression.SEPARATOR */)) {
2097 inputValue = String(inputValue);
2098 const localeDecimalMarker = this._maskService.currentLocaleDecimalMarker();
2099 if (!Array.isArray(this._maskService.decimalMarker)) {
2100 inputValue =
2101 this._maskService.decimalMarker !== localeDecimalMarker
2102 ? inputValue.replace(localeDecimalMarker, this._maskService.decimalMarker)
2103 : inputValue;
2104 }
2105 if (this._maskService.leadZero &&
2106 inputValue &&
2107 this.maskExpression &&
2108 this.dropSpecialCharacters !== false) {
2109 inputValue = this._maskService._checkPrecision(this._maskService.maskExpression, inputValue);
2110 }
2111 if (this.decimalMarker === "," /* MaskExpression.COMMA */ ||
2112 (Array.isArray(this._maskService.decimalMarker) &&
2113 this.thousandSeparator === "." /* MaskExpression.DOT */)) {
2114 inputValue = inputValue
2115 .toString()
2116 .replace("." /* MaskExpression.DOT */, "," /* MaskExpression.COMMA */);
2117 }
2118 if (this.maskExpression?.startsWith("separator" /* MaskExpression.SEPARATOR */) && this.leadZero) {
2119 requestAnimationFrame(() => {
2120 this._maskService.applyMask(inputValue?.toString() ?? '', this._maskService.maskExpression);
2121 });
2122 }
2123 this._maskService.isNumberValue = true;
2124 }
2125 if (typeof inputValue !== 'string') {
2126 inputValue = '';
2127 }
2128 this._inputValue = inputValue;
2129 this._setMask();
2130 if ((inputValue && this._maskService.maskExpression) ||
2131 (this._maskService.maskExpression &&
2132 (this._maskService.prefix || this._maskService.showMaskTyped))) {
2133 // Let the service we know we are writing value so that triggering onChange function won't happen during applyMask
2134 typeof this.inputTransformFn !== 'function'
2135 ? (this._maskService.writingValue = true)
2136 : '';
2137 this._maskService.formElementProperty = [
2138 'value',
2139 this._maskService.applyMask(inputValue, this._maskService.maskExpression),
2140 ];
2141 // Let the service know we've finished writing value
2142 typeof this.inputTransformFn !== 'function'
2143 ? (this._maskService.writingValue = false)
2144 : '';
2145 }
2146 else {
2147 this._maskService.formElementProperty = ['value', inputValue];
2148 }
2149 this._inputValue = inputValue;
2150 }
2151 else {
2152 console.warn('Ngx-mask writeValue work with string | number, your current value:', typeof controlValue);
2153 }
2154 }
2155 registerOnChange(fn) {
2156 this._maskService.onChange = this.onChange = fn;
2157 }
2158 registerOnTouched(fn) {
2159 this.onTouch = fn;
2160 }
2161 _getActiveElement(document = this.document) {
2162 const shadowRootEl = document?.activeElement?.shadowRoot;
2163 if (!shadowRootEl?.activeElement) {
2164 return document.activeElement;
2165 }
2166 else {
2167 return this._getActiveElement(shadowRootEl);
2168 }
2169 }
2170 checkSelectionOnDeletion(el) {
2171 el.selectionStart = Math.min(Math.max(this.prefix.length, el.selectionStart), this._inputValue.length - this.suffix.length);
2172 el.selectionEnd = Math.min(Math.max(this.prefix.length, el.selectionEnd), this._inputValue.length - this.suffix.length);
2173 }
2174 /** It disables the input element */
2175 setDisabledState(isDisabled) {
2176 this._maskService.formElementProperty = ['disabled', isDisabled];
2177 }
2178 // eslint-disable-next-line @typescript-eslint/no-explicit-any
2179 _applyMask() {
2180 this._maskService.maskExpression = this._maskService._repeatPatternSymbols(this._maskValue || '');
2181 this._maskService.formElementProperty = [
2182 'value',
2183 this._maskService.applyMask(this._inputValue, this._maskService.maskExpression),
2184 ];
2185 }
2186 _validateTime(value) {
2187 const rowMaskLen = this._maskValue
2188 .split("" /* MaskExpression.EMPTY_STRING */)
2189 .filter((s) => s !== ':').length;
2190 if (!value) {
2191 return null; // Don't validate empty values to allow for optional form control
2192 }
2193 if ((+(value[value.length - 1] ?? -1) === 0 && value.length < rowMaskLen) ||
2194 value.length <= rowMaskLen - 2) {
2195 return this._createValidationError(value);
2196 }
2197 return null;
2198 }
2199 _getActualInputLength() {
2200 return (this._maskService.actualValue.length ||
2201 this._maskService.actualValue.length + this._maskService.prefix.length);
2202 }
2203 _createValidationError(actualValue) {
2204 return {
2205 mask: {
2206 requiredMask: this._maskValue,
2207 actualValue,
2208 },
2209 };
2210 }
2211 _setMask() {
2212 this._maskExpressionArray.some((mask) => {
2213 const specialChart = mask
2214 .split("" /* MaskExpression.EMPTY_STRING */)
2215 .some((char) => this._maskService.specialCharacters.includes(char));
2216 if ((specialChart &&
2217 this._inputValue &&
2218 this._areAllCharactersInEachStringSame(this._maskExpressionArray)) ||
2219 mask.includes("{" /* MaskExpression.CURLY_BRACKETS_LEFT */)) {
2220 const test = this._maskService.removeMask(this._inputValue)?.length <=
2221 this._maskService.removeMask(mask)?.length;
2222 if (test) {
2223 this._maskValue =
2224 this.maskExpression =
2225 this._maskService.maskExpression =
2226 mask.includes("{" /* MaskExpression.CURLY_BRACKETS_LEFT */)
2227 ? this._maskService._repeatPatternSymbols(mask)
2228 : mask;
2229 return test;
2230 }
2231 else {
2232 if (this._code === "Backspace" /* MaskExpression.BACKSPACE */) {
2233 this._allowFewMaskChangeMask = true;
2234 }
2235 const expression = this._maskExpressionArray[this._maskExpressionArray.length - 1] ??
2236 "" /* MaskExpression.EMPTY_STRING */;
2237 this._maskValue =
2238 this.maskExpression =
2239 this._maskService.maskExpression =
2240 expression.includes("{" /* MaskExpression.CURLY_BRACKETS_LEFT */)
2241 ? this._maskService._repeatPatternSymbols(expression)
2242 : expression;
2243 }
2244 }
2245 else {
2246 const check = this._maskService
2247 .removeMask(this._inputValue)
2248 ?.split("" /* MaskExpression.EMPTY_STRING */)
2249 .every((character, index) => {
2250 const indexMask = mask.charAt(index);
2251 return this._maskService._checkSymbolMask(character, indexMask);
2252 });
2253 if (check || this._justPasted) {
2254 this._maskValue = this.maskExpression = this._maskService.maskExpression = mask;
2255 return check;
2256 }
2257 }
2258 });
2259 }
2260 _areAllCharactersInEachStringSame(array) {
2261 const specialCharacters = this._maskService.specialCharacters;
2262 function removeSpecialCharacters(str) {
2263 const regex = new RegExp(`[${specialCharacters.map((ch) => `\\${ch}`).join('')}]`, 'g');
2264 return str.replace(regex, '');
2265 }
2266 const processedArr = array.map(removeSpecialCharacters);
2267 return processedArr.every((str) => {
2268 const uniqueCharacters = new Set(str);
2269 return uniqueCharacters.size === 1;
2270 });
2271 }
2272 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.1", ngImport: i0, type: NgxMaskDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2273 static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.1.1", type: NgxMaskDirective, isStandalone: true, selector: "input[mask], textarea[mask]", inputs: { maskExpression: ["mask", "maskExpression"], specialCharacters: "specialCharacters", patterns: "patterns", prefix: "prefix", suffix: "suffix", thousandSeparator: "thousandSeparator", decimalMarker: "decimalMarker", dropSpecialCharacters: "dropSpecialCharacters", hiddenInput: "hiddenInput", showMaskTyped: "showMaskTyped", placeHolderCharacter: "placeHolderCharacter", shownMaskExpression: "shownMaskExpression", showTemplate: "showTemplate", clearIfNotMatch: "clearIfNotMatch", validation: "validation", separatorLimit: "separatorLimit", allowNegativeNumbers: "allowNegativeNumbers", leadZeroDateTime: "leadZeroDateTime", leadZero: "leadZero", triggerOnMaskChange: "triggerOnMaskChange", apm: "apm", inputTransformFn: "inputTransformFn", outputTransformFn: "outputTransformFn", keepCharacterPositions: "keepCharacterPositions" }, outputs: { maskFilled: "maskFilled" }, host: { listeners: { "paste": "onPaste()", "focus": "onFocus($event)", "ngModelChange": "onModelChange($event)", "input": "onInput($event)", "compositionstart": "onCompositionStart($event)", "compositionend": "onCompositionEnd($event)", "blur": "onBlur($event)", "click": "onClick($event)", "keydown": "onKeyDown($event)" } }, providers: [
2274 {
2275 provide: NG_VALUE_ACCESSOR,
2276 useExisting: NgxMaskDirective,
2277 multi: true,
2278 },
2279 {
2280 provide: NG_VALIDATORS,
2281 useExisting: NgxMaskDirective,
2282 multi: true,
2283 },
2284 NgxMaskService,
2285 ], exportAs: ["mask", "ngxMask"], usesOnChanges: true, ngImport: i0 }); }
2286}
2287i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.1", ngImport: i0, type: NgxMaskDirective, decorators: [{
2288 type: Directive,
2289 args: [{
2290 selector: 'input[mask], textarea[mask]',
2291 standalone: true,
2292 providers: [
2293 {
2294 provide: NG_VALUE_ACCESSOR,
2295 useExisting: NgxMaskDirective,
2296 multi: true,
2297 },
2298 {
2299 provide: NG_VALIDATORS,
2300 useExisting: NgxMaskDirective,
2301 multi: true,
2302 },
2303 NgxMaskService,
2304 ],
2305 exportAs: 'mask,ngxMask',
2306 }]
2307 }], propDecorators: { maskExpression: [{
2308 type: Input,
2309 args: ['mask']
2310 }], specialCharacters: [{
2311 type: Input
2312 }], patterns: [{
2313 type: Input
2314 }], prefix: [{
2315 type: Input
2316 }], suffix: [{
2317 type: Input
2318 }], thousandSeparator: [{
2319 type: Input
2320 }], decimalMarker: [{
2321 type: Input
2322 }], dropSpecialCharacters: [{
2323 type: Input
2324 }], hiddenInput: [{
2325 type: Input
2326 }], showMaskTyped: [{
2327 type: Input
2328 }], placeHolderCharacter: [{
2329 type: Input
2330 }], shownMaskExpression: [{
2331 type: Input
2332 }], showTemplate: [{
2333 type: Input
2334 }], clearIfNotMatch: [{
2335 type: Input
2336 }], validation: [{
2337 type: Input
2338 }], separatorLimit: [{
2339 type: Input
2340 }], allowNegativeNumbers: [{
2341 type: Input
2342 }], leadZeroDateTime: [{
2343 type: Input
2344 }], leadZero: [{
2345 type: Input
2346 }], triggerOnMaskChange: [{
2347 type: Input
2348 }], apm: [{
2349 type: Input
2350 }], inputTransformFn: [{
2351 type: Input
2352 }], outputTransformFn: [{
2353 type: Input
2354 }], keepCharacterPositions: [{
2355 type: Input
2356 }], maskFilled: [{
2357 type: Output
2358 }], onPaste: [{
2359 type: HostListener,
2360 args: ['paste']
2361 }], onFocus: [{
2362 type: HostListener,
2363 args: ['focus', ['$event']]
2364 }], onModelChange: [{
2365 type: HostListener,
2366 args: ['ngModelChange', ['$event']]
2367 }], onInput: [{
2368 type: HostListener,
2369 args: ['input', ['$event']]
2370 }], onCompositionStart: [{
2371 type: HostListener,
2372 args: ['compositionstart', ['$event']]
2373 }], onCompositionEnd: [{
2374 type: HostListener,
2375 args: ['compositionend', ['$event']]
2376 }], onBlur: [{
2377 type: HostListener,
2378 args: ['blur', ['$event']]
2379 }], onClick: [{
2380 type: HostListener,
2381 args: ['click', ['$event']]
2382 }], onKeyDown: [{
2383 type: HostListener,
2384 args: ['keydown', ['$event']]
2385 }] } });
2386
2387class NgxMaskPipe {
2388 constructor() {
2389 this.defaultOptions = inject(NGX_MASK_CONFIG);
2390 this._maskService = inject(NgxMaskService);
2391 this._maskExpressionArray = [];
2392 this.mask = '';
2393 }
2394 transform(value, mask, { patterns, ...config } = {}) {
2395 const currentConfig = {
2396 maskExpression: mask,
2397 ...this.defaultOptions,
2398 ...config,
2399 patterns: {
2400 ...this._maskService.patterns,
2401 ...patterns,
2402 },
2403 };
2404 Object.entries(currentConfig).forEach(([key, value]) => {
2405 //eslint-disable-next-line @typescript-eslint/no-explicit-any
2406 this._maskService[key] = value;
2407 });
2408 if (mask.includes('||')) {
2409 if (mask.split('||').length > 1) {
2410 this._maskExpressionArray = mask.split('||').sort((a, b) => {
2411 return a.length - b.length;
2412 });
2413 this._setMask(value);
2414 return this._maskService.applyMask(`${value}`, this.mask);
2415 }
2416 else {
2417 this._maskExpressionArray = [];
2418 return this._maskService.applyMask(`${value}`, this.mask);
2419 }
2420 }
2421 if (mask.includes("{" /* MaskExpression.CURLY_BRACKETS_LEFT */)) {
2422 return this._maskService.applyMask(`${value}`, this._maskService._repeatPatternSymbols(mask));
2423 }
2424 if (mask.startsWith("separator" /* MaskExpression.SEPARATOR */)) {
2425 if (config.decimalMarker) {
2426 this._maskService.decimalMarker = config.decimalMarker;
2427 }
2428 if (config.thousandSeparator) {
2429 this._maskService.thousandSeparator = config.thousandSeparator;
2430 }
2431 if (config.leadZero) {
2432 this._maskService.leadZero = config.leadZero;
2433 }
2434 value = String(value);
2435 const localeDecimalMarker = this._maskService.currentLocaleDecimalMarker();
2436 if (!Array.isArray(this._maskService.decimalMarker)) {
2437 value =
2438 this._maskService.decimalMarker !== localeDecimalMarker
2439 ? value.replace(localeDecimalMarker, this._maskService.decimalMarker)
2440 : value;
2441 }
2442 if (this._maskService.leadZero &&
2443 value &&
2444 this._maskService.dropSpecialCharacters !== false) {
2445 value = this._maskService._checkPrecision(mask, value);
2446 }
2447 if (this._maskService.decimalMarker === "," /* MaskExpression.COMMA */) {
2448 value = value.toString().replace("." /* MaskExpression.DOT */, "," /* MaskExpression.COMMA */);
2449 }
2450 this._maskService.isNumberValue = true;
2451 }
2452 if (value === null || value === undefined) {
2453 return this._maskService.applyMask('', mask);
2454 }
2455 return this._maskService.applyMask(`${value}`, mask);
2456 }
2457 _setMask(value) {
2458 if (this._maskExpressionArray.length > 0) {
2459 this._maskExpressionArray.some((mask) => {
2460 const test = this._maskService.removeMask(value)?.length <=
2461 this._maskService.removeMask(mask)?.length;
2462 if (value && test) {
2463 this.mask = mask;
2464 return test;
2465 }
2466 else {
2467 const expression = this._maskExpressionArray[this._maskExpressionArray.length - 1] ??
2468 "" /* MaskExpression.EMPTY_STRING */;
2469 this.mask = expression;
2470 }
2471 });
2472 }
2473 }
2474 static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.1", ngImport: i0, type: NgxMaskPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
2475 static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.1.1", ngImport: i0, type: NgxMaskPipe, isStandalone: true, name: "mask" }); }
2476}
2477i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.1", ngImport: i0, type: NgxMaskPipe, decorators: [{
2478 type: Pipe,
2479 args: [{
2480 name: 'mask',
2481 pure: true,
2482 standalone: true,
2483 }]
2484 }] });
2485
2486/**
2487 * Generated bundle index. Do not edit.
2488 */
2489
2490export { INITIAL_CONFIG, NEW_CONFIG, NGX_MASK_CONFIG, NgxMaskDirective, NgxMaskPipe, NgxMaskService, initialConfig, provideEnvironmentNgxMask, provideNgxMask, timeMasks, withoutValidation };
2491//# sourceMappingURL=ngx-mask.mjs.map