ngx-mask 16.0.2 → 16.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -241,7 +241,6 @@ class NgxMaskApplierService {
241
241
  }
242
242
  }
243
243
  if (maskExpression.startsWith('percent')) {
244
- //ogranich posle tochki
245
244
  if (inputValue.match('[a-z]|[A-Z]') ||
246
245
  // eslint-disable-next-line no-useless-escape
247
246
  inputValue.match(/[-!$%^&*()_+|~=`{}\[\]:";'<>?,\/.]/)) {
@@ -377,6 +376,8 @@ class NgxMaskApplierService {
377
376
  else if (this._checkSymbolMask(inputSymbol, maskExpression[cursor] ?? '')) {
378
377
  if (maskExpression[cursor] === 'H') {
379
378
  if (Number(inputSymbol) > 2) {
379
+ // eslint-disable-next-line no-param-reassign
380
+ position = position + 1;
380
381
  cursor += 1;
381
382
  this._shiftStep(maskExpression, cursor, inputArray.length);
382
383
  i--;
@@ -387,25 +388,24 @@ class NgxMaskApplierService {
387
388
  }
388
389
  }
389
390
  if (maskExpression[cursor] === 'h') {
390
- if (result === '2' && Number(inputSymbol) > 3) {
391
+ if ((result === '2' && Number(inputSymbol) > 3) ||
392
+ ((result.slice(cursor - 2, cursor) === '2' ||
393
+ result.slice(cursor - 3, cursor) === '2' ||
394
+ result.slice(cursor - 4, cursor) === '2' ||
395
+ result.slice(cursor - 1, cursor) === '2') &&
396
+ Number(inputSymbol) > 3 &&
397
+ cursor > 10)) {
398
+ // eslint-disable-next-line no-param-reassign
399
+ position = position + 1;
391
400
  cursor += 1;
392
401
  i--;
393
402
  continue;
394
403
  }
395
404
  }
396
- if (maskExpression[cursor] === 'm') {
397
- if (Number(inputSymbol) > 5) {
398
- cursor += 1;
399
- this._shiftStep(maskExpression, cursor, inputArray.length);
400
- i--;
401
- if (this.leadZeroDateTime) {
402
- result += '0';
403
- }
404
- continue;
405
- }
406
- }
407
- if (maskExpression[cursor] === 's') {
405
+ if (maskExpression[cursor] === 'm' || maskExpression[cursor] === 's') {
408
406
  if (Number(inputSymbol) > 5) {
407
+ // eslint-disable-next-line no-param-reassign
408
+ position = position + 1;
409
409
  cursor += 1;
410
410
  this._shiftStep(maskExpression, cursor, inputArray.length);
411
411
  i--;
@@ -416,31 +416,34 @@ class NgxMaskApplierService {
416
416
  }
417
417
  }
418
418
  const daysCount = 31;
419
+ const inputValueCursor = inputValue[cursor];
420
+ const inputValueCursorPlusOne = inputValue[cursor + 1];
421
+ const inputValueCursorPlusTwo = inputValue[cursor + 2];
422
+ const inputValueCursorMinusOne = inputValue[cursor - 1];
423
+ const inputValueCursorMinusTwo = inputValue[cursor - 2];
424
+ const inputValueCursorMinusThree = inputValue[cursor - 3];
425
+ const inputValueSliceMinusThreeMinusOne = inputValue.slice(cursor - 3, cursor - 1);
426
+ const inputValueSliceMinusOnePlusOne = inputValue.slice(cursor - 1, cursor + 1);
427
+ const inputValueSliceCursorPlusTwo = inputValue.slice(cursor, cursor + 2);
428
+ const inputValueSliceMinusTwoCursor = inputValue.slice(cursor - 2, cursor);
419
429
  if (maskExpression[cursor] === 'd') {
420
430
  const maskStartWithMonth = maskExpression.slice(0, 2) === 'M0';
421
431
  const startWithMonthInput = maskExpression.slice(0, 2) === 'M0' &&
422
- (inputValue[cursor - 2] === '/' ||
423
- inputValue[cursor - 2] === '.' ||
424
- inputValue[cursor - 2] === '-');
432
+ this.specialCharacters.includes(inputValueCursorMinusTwo);
425
433
  if ((Number(inputSymbol) > 3 && this.leadZeroDateTime) ||
426
434
  (!maskStartWithMonth &&
427
- (Number(inputValue.slice(cursor, cursor + 2)) > daysCount ||
428
- Number(inputValue.slice(cursor - 1, cursor + 1)) > daysCount ||
429
- inputValue[cursor + 1] === '/' ||
430
- inputValue[cursor + 1] === '-')) ||
435
+ (Number(inputValueSliceCursorPlusTwo) > daysCount ||
436
+ Number(inputValueSliceMinusOnePlusOne) > daysCount ||
437
+ this.specialCharacters.includes(inputValueCursorPlusOne))) ||
431
438
  (startWithMonthInput
432
- ? Number(inputValue.slice(cursor - 1, cursor + 1)) > daysCount ||
433
- (inputValue[cursor] !== '/' &&
434
- (inputValue[cursor + 2] === '.' ||
435
- inputValue[cursor + 2] === '/' ||
436
- inputValue[cursor + 2] === '-')) ||
437
- inputValue[cursor] === '.' ||
438
- inputValue[cursor] === '/' ||
439
- inputValue[cursor] === '-'
440
- : Number(inputValue.slice(cursor, cursor + 2)) > daysCount ||
441
- inputValue[cursor + 1] === '/' ||
442
- inputValue[cursor + 1] === '-' ||
443
- inputValue[cursor + 1] === '.')) {
439
+ ? Number(inputValueSliceMinusOnePlusOne) > daysCount ||
440
+ (!this.specialCharacters.includes(inputValueCursor) &&
441
+ this.specialCharacters.includes(inputValueCursorPlusTwo)) ||
442
+ this.specialCharacters.includes(inputValueCursor)
443
+ : Number(inputValueSliceCursorPlusTwo) > daysCount ||
444
+ this.specialCharacters.includes(inputValueCursorPlusOne))) {
445
+ // eslint-disable-next-line no-param-reassign
446
+ position = position + 1;
444
447
  cursor += 1;
445
448
  this._shiftStep(maskExpression, cursor, inputArray.length);
446
449
  i--;
@@ -455,43 +458,39 @@ class NgxMaskApplierService {
455
458
  // mask without day
456
459
  const withoutDays = cursor === 0 &&
457
460
  (Number(inputSymbol) > 2 ||
458
- Number(inputValue.slice(cursor, cursor + 2)) > monthsCount ||
459
- inputValue[cursor + 1] === '/');
461
+ Number(inputValueSliceCursorPlusTwo) > monthsCount ||
462
+ this.specialCharacters.includes(inputValueCursorPlusOne));
460
463
  // day<10 && month<12 for input
461
- const day1monthInput = inputValue.slice(cursor - 3, cursor - 1).includes('/') &&
462
- ((inputValue[cursor - 2] === '/' &&
463
- Number(inputValue.slice(cursor - 1, cursor + 1)) > monthsCount &&
464
- inputValue[cursor] !== '/') ||
465
- inputValue[cursor] === '/' ||
466
- inputValue[cursor] === '-' ||
467
- (inputValue[cursor - 3] === '/' &&
468
- Number(inputValue.slice(cursor - 2, cursor)) > monthsCount &&
469
- inputValue[cursor - 1] !== '/') ||
470
- inputValue[cursor - 1] === '/' ||
471
- inputValue[cursor - 1] === '-');
464
+ const specialChart = maskExpression.slice(cursor + 2, cursor + 3);
465
+ const day1monthInput = inputValueSliceMinusThreeMinusOne.includes(specialChart) &&
466
+ ((this.specialCharacters.includes(inputValueCursorMinusTwo) &&
467
+ Number(inputValueSliceMinusOnePlusOne) > monthsCount &&
468
+ !this.specialCharacters.includes(inputValueCursor)) ||
469
+ this.specialCharacters.includes(inputValueCursor) ||
470
+ (this.specialCharacters.includes(inputValueCursorMinusThree) &&
471
+ Number(inputValueSliceMinusTwoCursor) > monthsCount &&
472
+ !this.specialCharacters.includes(inputValueCursorMinusOne)) ||
473
+ this.specialCharacters.includes(inputValueCursorMinusOne));
472
474
  // month<12 && day<10 for input
473
- const day2monthInput = Number(inputValue.slice(cursor - 3, cursor - 1)) <= daysCount &&
474
- !inputValue.slice(cursor - 3, cursor - 1).includes('/') &&
475
- (inputValue[cursor - 1] === '/' || inputValue[cursor - 1] === '-') &&
476
- (Number(inputValue.slice(cursor, cursor + 2)) > monthsCount ||
477
- inputValue[cursor + 1] === '/' ||
478
- inputValue[cursor + 1] === '-');
475
+ const day2monthInput = Number(inputValueSliceMinusThreeMinusOne) <= daysCount &&
476
+ !this.specialCharacters.includes(inputValueSliceMinusThreeMinusOne) &&
477
+ this.specialCharacters.includes(inputValueCursorMinusOne) &&
478
+ (Number(inputValueSliceCursorPlusTwo) > monthsCount ||
479
+ this.specialCharacters.includes(inputValueCursorPlusOne));
479
480
  // cursor === 5 && without days
480
- const day2monthInputDot = (Number(inputValue.slice(cursor, cursor + 2)) > monthsCount &&
481
- cursor === 5) ||
482
- inputValue[cursor + 1] === '.' ||
483
- inputValue[cursor + 1] === '-' ||
484
- inputValue[cursor + 1] === '/';
485
- // day<10 && month<12 for paste whole data
486
- const day1monthPaste = Number(inputValue.slice(cursor - 3, cursor - 1)) > daysCount &&
487
- !inputValue.slice(cursor - 3, cursor - 1).includes('/') &&
488
- !inputValue.slice(cursor - 2, cursor).includes('/') &&
489
- Number(inputValue.slice(cursor - 2, cursor)) > monthsCount;
481
+ const day2monthInputDot = (Number(inputValueSliceCursorPlusTwo) > monthsCount && cursor === 5) ||
482
+ (this.specialCharacters.includes(inputValueCursorPlusOne) &&
483
+ cursor === 5);
484
+ // // day<10 && month<12 for paste whole data
485
+ const day1monthPaste = Number(inputValueSliceMinusThreeMinusOne) > daysCount &&
486
+ !this.specialCharacters.includes(inputValueSliceMinusThreeMinusOne) &&
487
+ !this.specialCharacters.includes(inputValueSliceMinusTwoCursor) &&
488
+ Number(inputValueSliceMinusTwoCursor) > monthsCount;
490
489
  // 10<day<31 && month<12 for paste whole data
491
- const day2monthPaste = Number(inputValue.slice(cursor - 3, cursor - 1)) <= daysCount &&
492
- !inputValue.slice(cursor - 3, cursor - 1).includes('/') &&
493
- inputValue[cursor - 1] !== '/' &&
494
- Number(inputValue.slice(cursor - 1, cursor + 1)) > monthsCount;
490
+ const day2monthPaste = Number(inputValueSliceMinusThreeMinusOne) <= daysCount &&
491
+ !this.specialCharacters.includes(inputValueSliceMinusThreeMinusOne) &&
492
+ !this.specialCharacters.includes(inputValueCursorMinusOne) &&
493
+ Number(inputValueSliceMinusOnePlusOne) > monthsCount;
495
494
  if ((Number(inputSymbol) > 1 && this.leadZeroDateTime) ||
496
495
  withoutDays ||
497
496
  day1monthInput ||
@@ -499,6 +498,8 @@ class NgxMaskApplierService {
499
498
  day1monthPaste ||
500
499
  day2monthInput ||
501
500
  day2monthInputDot) {
501
+ // eslint-disable-next-line no-param-reassign
502
+ position = position + 1;
502
503
  cursor += 1;
503
504
  this._shiftStep(maskExpression, cursor, inputArray.length);
504
505
  i--;
@@ -1134,6 +1135,8 @@ class NgxMaskDirective {
1134
1135
  this._position = null;
1135
1136
  this._maskExpressionArray = [];
1136
1137
  this._justPasted = false;
1138
+ /**For IME composition event */
1139
+ this._isComposing = false;
1137
1140
  this.document = inject(DOCUMENT);
1138
1141
  this._maskService = inject(NgxMaskService, { self: true });
1139
1142
  this._config = inject(NGX_MASK_CONFIG);
@@ -1320,6 +1323,9 @@ class NgxMaskDirective {
1320
1323
  }
1321
1324
  }
1322
1325
  onInput(e) {
1326
+ // If IME is composing text, we wait for the composed text.
1327
+ if (this._isComposing)
1328
+ return;
1323
1329
  const el = e.target;
1324
1330
  this._inputValue = el.value;
1325
1331
  this._setMask();
@@ -1362,6 +1368,16 @@ class NgxMaskDirective {
1362
1368
  el.setSelectionRange(positionToApply, positionToApply);
1363
1369
  this._position = null;
1364
1370
  }
1371
+ // IME starts
1372
+ onCompositionStart() {
1373
+ this._isComposing = true;
1374
+ }
1375
+ // IME completes
1376
+ onCompositionEnd(e) {
1377
+ this._isComposing = false;
1378
+ this._justPasted = true;
1379
+ this.onInput(e);
1380
+ }
1365
1381
  onBlur() {
1366
1382
  if (this._maskValue) {
1367
1383
  this._maskService.clearIfNotMatchFn();
@@ -1424,18 +1440,24 @@ class NgxMaskDirective {
1424
1440
  if (!this._maskValue) {
1425
1441
  return;
1426
1442
  }
1443
+ if (this._isComposing) {
1444
+ // User finalize their choice from IME composition, so trigger onInput() for the composed text.
1445
+ if (e.key === 'Enter')
1446
+ this.onCompositionEnd(e);
1447
+ return;
1448
+ }
1427
1449
  this._code = e.code ? e.code : e.key;
1428
1450
  const el = e.target;
1429
1451
  this._inputValue = el.value;
1430
1452
  this._setMask();
1431
- if (e.keyCode === 38) {
1453
+ if (e.key === 'ArrowUp') {
1432
1454
  e.preventDefault();
1433
1455
  }
1434
- if (e.keyCode === 37 || e.keyCode === 8 || e.keyCode === 46) {
1435
- if (e.keyCode === 8 && el.value.length === 0) {
1456
+ if (e.key === 'ArrowLeft' || e.key === 'Backspace' || e.key === 'Delete') {
1457
+ if (e.key === 'Backspace' && el.value.length === 0) {
1436
1458
  el.selectionStart = el.selectionEnd;
1437
1459
  }
1438
- if (e.keyCode === 8 && el.selectionStart !== 0) {
1460
+ if (e.key === 'Backspace' && el.selectionStart !== 0) {
1439
1461
  // If specialChars is false, (shouldn't ever happen) then set to the defaults
1440
1462
  this.specialCharacters = this.specialCharacters?.length
1441
1463
  ? this.specialCharacters
@@ -1462,7 +1484,7 @@ class NgxMaskDirective {
1462
1484
  e.preventDefault();
1463
1485
  }
1464
1486
  const cursorStart = el.selectionStart;
1465
- if (e.keyCode === 8 &&
1487
+ if (e.key === 'Backspace' &&
1466
1488
  !el.readOnly &&
1467
1489
  cursorStart === 0 &&
1468
1490
  el.selectionEnd === el.value.length &&
@@ -1476,8 +1498,8 @@ class NgxMaskDirective {
1476
1498
  this._inputValue.length - this.suffix.length < el.selectionStart) {
1477
1499
  el.setSelectionRange(this._inputValue.length - this.suffix.length, this._inputValue.length);
1478
1500
  }
1479
- else if ((e.keyCode === 65 && e.ctrlKey) ||
1480
- (e.keyCode === 65 && e.metaKey) // Cmd + A (Mac)
1501
+ else if ((e.code === 'KeyA' && e.ctrlKey) ||
1502
+ (e.code === 'KeyA' && e.metaKey) // Cmd + A (Mac)
1481
1503
  ) {
1482
1504
  el.setSelectionRange(0, this._getActualInputLength());
1483
1505
  e.preventDefault();
@@ -1497,12 +1519,12 @@ class NgxMaskDirective {
1497
1519
  if (typeof inputValue === 'number' || this._maskValue.startsWith('separator')) {
1498
1520
  // eslint-disable-next-line no-param-reassign
1499
1521
  inputValue = this._maskService.numberToString(inputValue);
1500
- if (!Array.isArray(this.decimalMarker)) {
1522
+ if (!Array.isArray(this._maskService.decimalMarker)) {
1501
1523
  const localeDecimalMarker = this._currentLocaleDecimalMarker();
1502
1524
  // eslint-disable-next-line no-param-reassign
1503
1525
  inputValue =
1504
- this.decimalMarker !== localeDecimalMarker
1505
- ? inputValue.replace(localeDecimalMarker, this.decimalMarker)
1526
+ this._maskService.decimalMarker !== localeDecimalMarker
1527
+ ? inputValue.replace(localeDecimalMarker, this._maskService.decimalMarker)
1506
1528
  : inputValue;
1507
1529
  }
1508
1530
  this._maskService.isNumberValue = true;
@@ -1629,7 +1651,7 @@ class NgxMaskDirective {
1629
1651
  return (1.1).toLocaleString().substring(1, 2);
1630
1652
  }
1631
1653
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: NgxMaskDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1632
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.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", triggerOnMaskChange: "triggerOnMaskChange" }, outputs: { maskFilled: "maskFilled" }, host: { listeners: { "paste": "onPaste()", "ngModelChange": "onModelChange($event)", "input": "onInput($event)", "blur": "onBlur()", "click": "onClick($event)", "keydown": "onKeyDown($event)" } }, providers: [
1654
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.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", triggerOnMaskChange: "triggerOnMaskChange" }, outputs: { maskFilled: "maskFilled" }, host: { listeners: { "paste": "onPaste()", "ngModelChange": "onModelChange($event)", "input": "onInput($event)", "compositionstart": "onCompositionStart($event)", "compositionend": "onCompositionEnd($event)", "blur": "onBlur()", "click": "onClick($event)", "keydown": "onKeyDown($event)" } }, providers: [
1633
1655
  {
1634
1656
  provide: NG_VALUE_ACCESSOR,
1635
1657
  useExisting: NgxMaskDirective,
@@ -1713,6 +1735,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImpor
1713
1735
  }], onInput: [{
1714
1736
  type: HostListener,
1715
1737
  args: ['input', ['$event']]
1738
+ }], onCompositionStart: [{
1739
+ type: HostListener,
1740
+ args: ['compositionstart', ['$event']]
1741
+ }], onCompositionEnd: [{
1742
+ type: HostListener,
1743
+ args: ['compositionend', ['$event']]
1716
1744
  }], onBlur: [{
1717
1745
  type: HostListener,
1718
1746
  args: ['blur']