ngx-mask
Version:
Input masking for modern Angular — Reactive, template-driven and Signal Forms, zoneless and SSR ready. Dates, numbers, separators, custom patterns.
1 lines • 357 kB
Source Map (JSON)
{"version":3,"file":"ngx-mask.mjs","names":[],"sources":["../../../projects/ngx-mask-lib/src/lib/ngx-mask-expression.enum.ts","../../../projects/ngx-mask-lib/src/lib/ngx-mask.config.ts","../../../projects/ngx-mask-lib/src/lib/ngx-mask.utils.ts","../../../projects/ngx-mask-lib/src/lib/mask-handlers/cpf-cnpj.handler.ts","../../../projects/ngx-mask-lib/src/lib/caret/date-overflow.ts","../../../projects/ngx-mask-lib/src/lib/mask-handlers/generic-pattern.handler.ts","../../../projects/ngx-mask-lib/src/lib/mask-handlers/ip.handler.ts","../../../projects/ngx-mask-lib/src/lib/mask-handlers/percent.handler.ts","../../../projects/ngx-mask-lib/src/lib/mask-handlers/separator.handler.ts","../../../projects/ngx-mask-lib/src/lib/mask-handlers/mask-handlers.registry.ts","../../../projects/ngx-mask-lib/src/lib/ngx-mask-applier.service.ts","../../../projects/ngx-mask-lib/src/lib/ngx-mask.service.ts","../../../projects/ngx-mask-lib/src/lib/ngx-mask.providers.ts","../../../projects/ngx-mask-lib/src/lib/caret/keep-character-positions.ts","../../../projects/ngx-mask-lib/src/lib/ngx-mask.directive.ts","../../../projects/ngx-mask-lib/src/lib/ngx-mask.pipe.ts"],"sourcesContent":["export const enum MaskExpression {\n SEPARATOR = 'separator',\n PERCENT = 'percent',\n IP = 'IP',\n CPF_CNPJ = 'CPF_CNPJ',\n CPF_CNPJ_ALPHA = 'CPF_CNPJ_ALPHA',\n MONTH = 'M',\n MONTHS = 'M0',\n MINUTE = 'm',\n HOUR = 'h',\n HOURS = 'H',\n MINUTES = 'm0',\n HOURS_HOUR = 'Hh',\n SECONDS = 's0',\n HOURS_MINUTES_SECONDS = 'Hh:m0:s0',\n EMAIL_MASK = 'A*@A*.A*',\n HOURS_MINUTES = 'Hh:m0',\n MINUTES_SECONDS = 'm0:s0',\n DAYS_MONTHS_YEARS = 'd0/M0/0000',\n DAYS_MONTHS = 'd0/M0',\n DAYS = 'd0',\n DAY = 'd',\n SECOND = 's',\n LETTER_S = 'S',\n DOT = '.',\n NUMPAD_DECIMAL = 'Decimal',\n NUMPAD_DECIMAL_CODE = 'NumpadDecimal',\n COMMA = ',',\n CURLY_BRACKETS_LEFT = '{',\n CURLY_BRACKETS_RIGHT = '}',\n MINUS = '-',\n OR = '||',\n HASH = '#',\n EMPTY_STRING = '',\n SYMBOL_STAR = '*',\n SYMBOL_QUESTION = '?',\n SLASH = '/',\n WHITE_SPACE = ' ',\n NUMBER_ZERO = '0',\n NUMBER_NINE = '9',\n BACKSPACE = 'Backspace',\n DELETE = 'Delete',\n ARROW_LEFT = 'ArrowLeft',\n ARROW_UP = 'ArrowUp',\n DOUBLE_ZERO = '00',\n}\n","import { EventEmitter, InjectionToken } from '@angular/core';\nimport { MaskExpression } from './ngx-mask-expression.enum';\n\nexport type InputTransformFn = (value: unknown) => string | number;\n\nexport type OutputTransformFn = (value: string | number | undefined | null) => unknown;\n\n/** Single decimal marker character accepted when `decimalMarker` is given as an array. */\nexport type DecimalMarkerChar = '.' | ',';\n\nexport type NgxMaskConfig = {\n suffix: string;\n prefix: string;\n thousandSeparator: string;\n decimalMarker: DecimalMarkerChar | [DecimalMarkerChar, DecimalMarkerChar];\n clearIfNotMatch: boolean;\n showMaskTyped: boolean;\n placeHolderCharacter: string;\n shownMaskExpression: string;\n specialCharacters: string[] | readonly string[];\n dropSpecialCharacters: boolean | string[] | readonly string[];\n hiddenInput: boolean;\n validation: boolean;\n instantPrefix: boolean;\n separatorLimit: string;\n apm: boolean;\n allowNegativeNumbers: boolean;\n leadZeroDateTime: boolean;\n leadZero: boolean;\n /**\n * Opt-in \"banking\" typing mode for separator masks with a fixed precision\n * (`separator.N`, N > 0): typed digits fill the value from the decimal end,\n * ATM/calculator style (5 -> 0.05 -> 0.57 -> 5.73); backspace shifts digits\n * back to the right. Pasted and model-written values keep the regular\n * separator formatting. Config-only option (provideNgxMask / pipe config) —\n * it has no directive input.\n */\n typeFromDecimals: boolean;\n triggerOnMaskChange: boolean;\n keepCharacterPositions: boolean;\n inputTransformFn: InputTransformFn;\n outputTransformFn: OutputTransformFn;\n maskFilled: EventEmitter<void>;\n /**\n * User-defined named mask aliases resolved at the DI-config level (static per injector).\n * When the `mask` input (or pipe mask argument) exactly matches an alias key, the aliased\n * expression is substituted before any other mask processing (including `||` multi-masks).\n * Alias keys must not shadow built-in tokens (IP, CPF_CNPJ, CPF_CNPJ_ALPHA, ...) — such\n * aliases are ignored with a one-time console warning.\n */\n maskAliases: Record<string, string>;\n /**\n * When set, this raw value is written through the regular mask pipeline on blur\n * whenever the control's unmasked value is empty (covers '', a bare prefix/suffix and\n * the showMaskTyped skeleton): the display shows the masked default and the model\n * receives the usual output (dropSpecialCharacters/outputTransformFn applied). The\n * write keeps the control's pristine state. `null` (default) keeps current behavior.\n */\n defaultValueOnBlur: string | null;\n patterns: Record<\n string,\n {\n pattern: RegExp;\n optional?: boolean;\n symbol?: string;\n }\n >;\n};\n\nexport type NgxMaskOptions = Partial<NgxMaskConfig>;\nexport const NGX_MASK_CONFIG = new InjectionToken<NgxMaskConfig>('ngx-mask config');\nexport const NEW_CONFIG = new InjectionToken<NgxMaskConfig>('new ngx-mask config');\nexport const INITIAL_CONFIG = new InjectionToken<NgxMaskConfig>('initial ngx-mask config');\n\nexport const initialConfig: NgxMaskConfig = {\n suffix: '',\n prefix: '',\n thousandSeparator: ' ',\n decimalMarker: ['.', ','],\n clearIfNotMatch: false,\n showMaskTyped: false,\n instantPrefix: false,\n placeHolderCharacter: '_',\n dropSpecialCharacters: true,\n hiddenInput: false,\n shownMaskExpression: '',\n separatorLimit: '',\n allowNegativeNumbers: false,\n validation: true,\n specialCharacters: ['-', '/', '(', ')', '.', ':', ' ', '+', ',', '@', '[', ']', '\"', \"'\"],\n leadZeroDateTime: false,\n apm: false,\n leadZero: false,\n typeFromDecimals: false,\n keepCharacterPositions: false,\n triggerOnMaskChange: false,\n inputTransformFn: (value: unknown) => value as string | number,\n outputTransformFn: (value: string | number | undefined | null) => value,\n maskFilled: new EventEmitter<void>(),\n maskAliases: {},\n defaultValueOnBlur: null,\n patterns: {\n '0': {\n pattern: new RegExp('\\\\d'),\n },\n '9': {\n pattern: new RegExp('\\\\d'),\n optional: true,\n },\n X: {\n pattern: new RegExp('\\\\d'),\n symbol: '*',\n },\n A: {\n pattern: new RegExp('[a-zA-Z0-9]'),\n },\n S: {\n pattern: new RegExp('[a-zA-Z]'),\n },\n U: {\n pattern: new RegExp('[A-Z]'),\n },\n L: {\n pattern: new RegExp('[a-z]'),\n },\n d: {\n pattern: new RegExp('\\\\d'),\n symbol: '*',\n },\n m: {\n pattern: new RegExp('\\\\d'),\n },\n M: {\n pattern: new RegExp('\\\\d'),\n symbol: '*',\n },\n H: {\n pattern: new RegExp('\\\\d'),\n },\n h: {\n pattern: new RegExp('\\\\d'),\n },\n s: {\n pattern: new RegExp('\\\\d'),\n },\n },\n};\n\n/**\n * Built-in mask tokens dispatched by exact equality (IP, CPF_CNPJ, CPF_CNPJ_ALPHA, email)\n * or by a reserved prefix (separator, percent) inside the mask pipeline. User-defined\n * aliases must not shadow them — substituting e.g. 'IP' early would break the built-in\n * exact-equality dispatch deep in the applier.\n */\nconst RESERVED_MASK_TOKENS: ReadonlySet<string> = new Set([\n MaskExpression.IP,\n MaskExpression.CPF_CNPJ,\n MaskExpression.CPF_CNPJ_ALPHA,\n MaskExpression.EMAIL_MASK,\n MaskExpression.SEPARATOR,\n MaskExpression.PERCENT,\n]);\n\n/** Tracks alias keys already warned about, so the shadowing warning fires once per key. */\nconst warnedShadowedAliases = new Set<string>();\n\n/**\n * Resolves a user-defined mask alias to its mask expression. Returns the input expression\n * unchanged when no alias matches or when the alias key shadows a built-in token (in which\n * case a console warning is emitted once per key and the built-in wins).\n */\nexport function resolveMaskAlias(\n maskExpression: string | null | undefined,\n maskAliases: Record<string, string> | undefined\n): string {\n const expression = maskExpression ?? MaskExpression.EMPTY_STRING;\n if (!expression || !maskAliases) {\n return expression;\n }\n const aliased = maskAliases[expression];\n if (typeof aliased !== 'string') {\n return expression;\n }\n if (RESERVED_MASK_TOKENS.has(expression)) {\n if (!warnedShadowedAliases.has(expression)) {\n warnedShadowedAliases.add(expression);\n // eslint-disable-next-line no-console\n console.warn(\n `ngx-mask: mask alias \"${expression}\" shadows a built-in mask token and is ignored. Rename the alias.`\n );\n }\n return expression;\n }\n return aliased;\n}\n\nexport const timeMasks: string[] = [\n MaskExpression.HOURS_MINUTES_SECONDS,\n MaskExpression.HOURS_MINUTES,\n MaskExpression.MINUTES_SECONDS,\n];\n\nexport const withoutValidation: string[] = [\n MaskExpression.PERCENT,\n MaskExpression.HOURS_HOUR,\n MaskExpression.SECONDS,\n MaskExpression.MINUTES,\n MaskExpression.SEPARATOR,\n MaskExpression.DAYS_MONTHS_YEARS,\n MaskExpression.DAYS_MONTHS,\n MaskExpression.DAYS,\n MaskExpression.MONTHS,\n];\n","import { MaskExpression } from './ngx-mask-expression.enum';\nimport type { DecimalMarkerChar, NgxMaskConfig } from './ngx-mask.config';\n\n/**\n * Escapes every character that has a special meaning in a regular expression. An unset\n * (null/undefined) value, e.g. from an unset dynamic config, escapes to the empty string.\n */\nexport function escapeRegExp(value: string | null | undefined): string {\n return (value ?? '').replace(/[.*+?^${}()|[\\]\\\\/-]/g, '\\\\$&');\n}\n\n/** The first index at or after `index` whose mask character is not a special character. */\nexport function nextFillableIndex(\n maskExpression: string,\n specialCharacters: readonly string[],\n index: number\n): number {\n let maskIdx = index;\n while (\n maskIdx < maskExpression.length &&\n specialCharacters.includes(maskExpression[maskIdx] ?? MaskExpression.EMPTY_STRING)\n ) {\n maskIdx += 1;\n }\n return maskIdx;\n}\n\n/** Returns the decimal digits of `value`, in order. */\nexport function digitsOf(value: string): string[] {\n return value.match(/\\d/g) ?? [];\n}\n\n/** A thousandSeparator holding a digit is ignored (becomes empty); any other value passes through. */\nexport function ignoreDigitSeparator<T extends string | null | undefined>(separator: T): T | '' {\n return separator && digitsOf(separator).length ? '' : separator;\n}\n\n/**\n * The single rule for \"which decimal marker is active\": the configured marker, or - for an\n * array - the first configured marker present in `value` that is not the thousandSeparator,\n * else the first configured marker that is not the thousandSeparator (#1653).\n */\nexport function activeDecimalMarker(\n value: string,\n decimalMarker: NgxMaskConfig['decimalMarker'],\n thousandSeparator: string\n): DecimalMarkerChar {\n if (!Array.isArray(decimalMarker)) {\n return decimalMarker;\n }\n const candidates = decimalMarker.filter((dm) => dm !== thousandSeparator);\n return candidates.find((dm) => value.includes(dm)) ?? candidates[0] ?? decimalMarker[0];\n}\n\n/** Whether `value` writes its decimals after a comma, under the configured decimalMarker. */\nexport function usesCommaDecimal(\n value: string,\n decimalMarker: NgxMaskConfig['decimalMarker'],\n thousandSeparator: string\n): boolean {\n return activeDecimalMarker(value, decimalMarker, thousandSeparator) === MaskExpression.COMMA;\n}\n\n/**\n * Turns a string already in the display format (`1.234,5` under thousandSeparator '.' and\n * decimalMarker ',') into the plain `1234.5`. Only a string holding BOTH the active\n * thousandSeparator and the active decimal marker is read that way; anything else (`1234567.5`,\n * `1.5`) keeps its dot-decimal reading.\n */\nexport function displayToPlainDecimal(\n value: string,\n decimalMarker: NgxMaskConfig['decimalMarker'],\n thousandSeparator: string\n): string {\n const marker = activeDecimalMarker(value, decimalMarker, thousandSeparator);\n if (\n !thousandSeparator ||\n marker === thousandSeparator ||\n !value.includes(thousandSeparator) ||\n !value.includes(marker)\n ) {\n return value;\n }\n return value\n .split(thousandSeparator)\n .join(MaskExpression.EMPTY_STRING)\n .replace(marker, MaskExpression.DOT);\n}\n\n/**\n * Whether `value` holds a `*`, the symbol that stands for a hidden character. A `*` thousandSeparator\n * of a separator mask is plain grouping text there, not a hidden character.\n */\nexport function containsStarSymbol(\n value: string,\n maskExpression: string,\n thousandSeparator: string\n): boolean {\n return (\n value.includes(MaskExpression.SYMBOL_STAR) &&\n !(\n maskExpression.startsWith(MaskExpression.SEPARATOR) &&\n thousandSeparator?.includes(MaskExpression.SYMBOL_STAR)\n )\n );\n}\n\ntype SeparatorFormat = Pick<\n NgxMaskConfig,\n 'thousandSeparator' | 'decimalMarker' | 'prefix' | 'suffix'\n>;\n\n/**\n * Re-expresses a separator value written with the `previous` thousandSeparator/decimalMarker in\n * the `current` ones, so reconfiguring a populated control keeps its number (`1 234.5` stays\n * 1234.5 as `1.234,5`) instead of reading the old markers with the new rules. The previous\n * prefix and suffix are set aside first: they may contain the very characters being swapped.\n */\nexport function retargetSeparatorValue(\n value: string,\n previous: SeparatorFormat,\n current: SeparatorFormat\n): string {\n const prefix = previous.prefix && value.startsWith(previous.prefix) ? previous.prefix : '';\n const suffix =\n previous.suffix && value.length >= prefix.length + previous.suffix.length\n ? value.endsWith(previous.suffix)\n ? previous.suffix\n : ''\n : '';\n const number = value.slice(prefix.length, value.length - suffix.length);\n const previousMarker = activeDecimalMarker(\n number,\n previous.decimalMarker,\n previous.thousandSeparator ?? MaskExpression.EMPTY_STRING\n );\n const ungrouped = previous.thousandSeparator\n ? number.split(previous.thousandSeparator).join(MaskExpression.EMPTY_STRING)\n : number;\n const retargeted = ungrouped.replace(\n previousMarker,\n activeDecimalMarker(ungrouped, current.decimalMarker, current.thousandSeparator)\n );\n return `${prefix ? current.prefix : ''}${retargeted}${suffix ? current.suffix : ''}`;\n}\n","import { MaskExpression } from '../ngx-mask-expression.enum';\nimport type { MaskHandlerFn } from './mask-handler.types';\n\n/** CPF_CNPJ / CPF_CNPJ_ALPHA pre-processor (moved verbatim from applyMask). Sets\n * `this.cpfCnpjError`, rewrites the mask, then falls through to the generic loop.\n * Discriminated by exact equality BEFORE any startsWith handler — the 'H' of HOURS\n * would otherwise catch CPF_CNPJ_ALPHA by substring (CODEBASE_NOTES #3/#4). */\nexport const cpfCnpjHandler: MaskHandlerFn = function (state, params) {\n const isCpfCnpjAlpha = state.maskExpression === MaskExpression.CPF_CNPJ_ALPHA;\n this.cpfCnpjError = params.arr.length !== 11 && params.arr.length !== 14;\n const valueHasAnyLetter = /[a-zA-Z]/.test(state.processedValue);\n if (valueHasAnyLetter && isCpfCnpjAlpha) {\n state.maskExpression = 'AA.AAA.AAA/AAAA-00';\n } else if (params.arr.length > 11) {\n state.maskExpression = isCpfCnpjAlpha ? 'AA.AAA.AAA/AAAA-00' : '00.000.000/0000-00';\n } else {\n state.maskExpression = '000.000.000-00';\n }\n return state;\n};\n","import { MaskExpression } from '../ngx-mask-expression.enum';\nimport { nextFillableIndex } from '../ngx-mask.utils';\n\n// #1488: a date/time field located within `maskExpression` for the generalized\n// caret-shift-past-separator fix (see `findDateTimeFieldAt`/`isFieldOverflowing`).\nexport type DateTimeField = {\n token: 'd' | 'M' | 'H' | 'h' | 'm' | 's';\n start: number; // index of the field's first char in maskExpression\n end: number; // index one past the field's digit run (start of separator/next field)\n};\n\n/**\n * #1488: locates the date/time field (DAY/MONTH/HOURS/HOUR/MINUTE/SECOND) that\n * `position` falls within, scanning `maskExpression` left-to-right. A field spans\n * its token plus its digit-pair companion — `0` for DAY/MONTH/MINUTE/SECOND (e.g.\n * `d0`, `M0`, `m0`, `s0`), or `HOUR` for the combined `Hh` hour field. Matches any\n * position from the field's first char up to and including its end (separator index),\n * so both a still-mid-typing caret and the just-completed field are covered — the\n * precise overflow decision (single first digit vs. completed 2-digit value) happens\n * in `isFieldOverflowing`. Returns null for non-date/time masks, a no-op for the caller.\n */\nexport function findDateTimeFieldAt(\n maskExpression: string,\n position: number\n): DateTimeField | null {\n const dateTimeTokens: readonly string[] = [\n MaskExpression.DAY,\n MaskExpression.MONTH,\n MaskExpression.HOURS,\n MaskExpression.HOUR,\n MaskExpression.MINUTE,\n MaskExpression.SECOND,\n ];\n let index = 0;\n while (index < maskExpression.length) {\n const token = maskExpression[index] ?? MaskExpression.EMPTY_STRING;\n if (dateTimeTokens.includes(token)) {\n const next = maskExpression[index + 1];\n const isCombinedHour =\n (token === MaskExpression.HOURS || token === MaskExpression.HOUR) &&\n next === MaskExpression.HOUR;\n const end =\n next === MaskExpression.NUMBER_ZERO || isCombinedHour ? index + 2 : index + 1;\n if (position >= index && position <= end) {\n return {\n token: token as DateTimeField['token'],\n start: index,\n end,\n };\n }\n index = end;\n continue;\n }\n index++;\n }\n return null;\n}\n\n/** Whether the mask has a day, month, hour, minute or second field. */\nexport function isDateTimeMask(maskExpression: string): boolean {\n for (let position = 0; position < maskExpression.length; position++) {\n if (findDateTimeFieldAt(maskExpression, position)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Per-token overflow thresholds, mirroring the ones `generic-pattern.handler.ts`\n * already establishes (day 31, month 12, hour 23/12 w/ apm, minute/second 59) — kept\n * as a small local table rather than importing from the handler (see design's\n * Rejected Alternatives: the directive and the handler stay on separate sides of the\n * display/parse boundary).\n *\n * Two overflow shapes are checked, mirroring how the handler itself decides mid-type:\n * - `firstDigitValue`: when `position` is exactly one char past the field's start (the\n * just-typed char is the field's first digit), an out-of-range first digit alone\n * (e.g. month digit `3`, day digit `4`) already triggers the handler's own leadZero\n * pad within this same keystroke — `el.value` hasn't caught up yet at this point in\n * the pipeline, so the raw typed digit (`inputValue`) must be read instead.\n * - `fieldValue`: once both digits of the field are present in `el.value`, an\n * out-of-range 2-digit value (e.g. day `33`, month `13`) triggers the shift directly.\n */\nexport function isFieldOverflowing(\n field: DateTimeField,\n position: number,\n elValue: string,\n inputValue: string,\n apm: boolean\n): boolean {\n const fieldValue = Number(elValue.slice(field.start, field.end));\n const isFirstDigitOfField = position === field.start + 1;\n const firstDigitValue = isFirstDigitOfField\n ? Number(inputValue.slice(position - 1, position))\n : NaN;\n switch (field.token) {\n case MaskExpression.DAY:\n return (fieldValue > 31 && fieldValue < 40) || firstDigitValue > 3;\n case MaskExpression.MONTH:\n return fieldValue > 12 || firstDigitValue > 1;\n case MaskExpression.HOURS:\n return apm\n ? fieldValue > 12 || firstDigitValue > 9\n : fieldValue > 23 || firstDigitValue > 2;\n case MaskExpression.HOUR:\n return apm ? fieldValue > 12 : fieldValue > 23;\n case MaskExpression.MINUTE:\n case MaskExpression.SECOND:\n return fieldValue > 59 || firstDigitValue > 5;\n default:\n return false;\n }\n}\n\n/**\n * The caret of a leadZeroDateTime mask: moved two chars on when the field at `position`\n * overflows, as the handler pads a zero in front of it and adds the separator.\n */\nexport function leadZeroDateTimeCaret(\n maskExpression: string,\n position: number,\n elValue: string,\n inputValue: string,\n apm: boolean\n): number {\n const field = findDateTimeFieldAt(maskExpression, position);\n return field && isFieldOverflowing(field, position, elValue, inputValue, apm)\n ? position + 2\n : position;\n}\n\n/**\n * The element value of a `d0/M0/0000` mask whose raw value already has its full length: the\n * character after the caret is dropped, so the typed one overwrites it. Returns null when the\n * edit does not meet that shape and the value stays. Kept for the edits `overwriteDateSlot` does\n * not take: a paste, and prefix, suffix and keepCharacterPositions masks.\n */\nexport function overwriteFullDateValue(\n maskExpression: string,\n inputValue: string,\n position: number,\n code: string\n): string | null {\n if (\n inputValue.length >= maskExpression.length - 1 &&\n code !== MaskExpression.BACKSPACE &&\n maskExpression === MaskExpression.DAYS_MONTHS_YEARS &&\n position < 10\n ) {\n const inputSymbol = inputValue.slice(position - 1, position);\n return inputValue.slice(0, position - 1) + inputSymbol + inputValue.slice(position + 1);\n }\n return null;\n}\n\n/** The edit `overwriteDateSlot` made: the value, the caret after it and the last index it touches. */\nexport type DateOverwrite = { value: string; position: number; end: number };\n\n/**\n * What `overwriteDateSlot` reads from the mask service. Structural, not a `Pick` of the service:\n * importing the service type here reorders unions in the emitted d.ts (see `userEdits`).\n */\nexport type DateSlotMask = {\n maskExpression: string;\n specialCharacters: string[] | readonly string[];\n leadZeroDateTime: boolean;\n apm: boolean;\n _checkSymbolMask: (inputSymbol: string, maskSymbol: string) => boolean;\n};\n\nconst FIELD_MAX: Readonly<Record<DateTimeField['token'], number>> = {\n d: 31,\n M: 12,\n H: 23,\n h: 23,\n m: 59,\n s: 59,\n};\n\n/**\n * A character typed into a date mask whose display is already full length overwrites the next\n * digit slot, skipping separators, so the digits that follow never shift. With leadZeroDateTime\n * a field the digit would push out of range, or a whole selected field the digit replaces, is\n * repaired: the digit keeps its slot and zero-fills (`3` over `15` is `30`) or, when it cannot be a\n * tens digit, is the whole field (`4` over `15` is `04`). A key the slot rejects leaves the display\n * as it was. Null leaves the edit to the caller: not one character typed into a full date, a\n * selection beyond one field, or an out-of-range field without leadZeroDateTime. `before` is the\n * display the keydown saw; only a selection needs it, as one character typed at a caret is\n * `elValue` without it, an edit without a keydown (dictation, insertText) included.\n */\nexport function overwriteDateSlot(\n svc: DateSlotMask,\n before: string,\n elValue: string,\n position: number\n): DateOverwrite | null {\n const mask = svc.maskExpression;\n const start = position - 1;\n // A value longer than the mask is read as one character typed at the caret of a full display\n // (a multi-character mid-value insertion into a shorter display is mis-read; base mangles it too).\n const display =\n elValue.length > mask.length ? elValue.slice(0, start) + elValue.slice(position) : before;\n // The end of the span the typed character replaced in `display` (a caret replaces nothing).\n const selEnd = display.length - elValue.length + position;\n const typed = elValue.charAt(start);\n const target = nextFillableIndex(mask, svc.specialCharacters, start);\n const slot = findDateTimeFieldAt(mask, target);\n // At a field boundary of a separator-less mask (`0000M0d0`) the slot belongs to the next field.\n const field = slot?.end === target ? findDateTimeFieldAt(mask, target + 1) : slot;\n if (\n !/[dM]/.test(mask) ||\n display.length !== mask.length ||\n // under showMaskTyped a placeholder slot takes the digit in sequence, not in place\n !/\\d/.test(display.charAt(target)) ||\n // a stale `before` (the keydown of the edit never fired): not the display of the selection\n elValue !== display.slice(0, start) + typed + display.slice(selEnd) ||\n // a selection stays within one field, and only leadZeroDateTime pads what it replaces\n selEnd > (field?.end ?? target + 1) ||\n (selEnd - start > 1 && !svc.leadZeroDateTime)\n ) {\n return null;\n }\n if (!svc._checkSymbolMask(typed, mask.charAt(target))) {\n // A key the slot rejects changes nothing, a selection included: `end` -1 touches no index.\n return { value: display, position: start, end: -1 };\n }\n let value = display.slice(0, target) + typed + display.slice(target + 1);\n let caret = target + 1;\n if (field) {\n const max = svc.apm && /[Hh]/.test(field.token) ? 12 : FIELD_MAX[field.token];\n // A one-digit field, or one still holding a placeholder (`4_` is NaN), is never out of range.\n const over = Number(value.slice(field.start, field.end)) > max;\n // A selection past the slot is a whole field.\n if (svc.leadZeroDateTime && (over || selEnd > caret)) {\n // The digit keeps its tens slot and zero-fills (`3` over `15` is `30`) when it can be\n // a tens digit; otherwise it is the whole field (`4` over `15` is `04`).\n const tens = target === field.start && Number(typed) * 10 <= max;\n value =\n display.slice(0, field.start) +\n (tens ? typed + '0' : '0' + typed) +\n display.slice(field.end);\n caret = tens ? caret : field.end;\n } else if (over) {\n return null;\n }\n }\n return { value, position: caret, end: caret };\n}\n\n/** The span of `value` that the user's last edit (keystroke, deletion, paste) changed. */\nexport type UserEdit = { value: string; start: number; end: number };\n\n// Keyed by the mask service, kept outside it so the published API carries no field for it. The key\n// is typed `object`: importing the service type here reorders unions in the emitted d.ts.\nconst userEdits = new WeakMap<object, UserEdit>();\n\n/**\n * Records the edit the directive is about to mask, `null` for an edit that changed no field. Only an\n * edit may turn a typed `00` day, month or 12-hour hour into `01` (leadZeroDateTime): a render of any\n * other value, e.g. a write or a re-render, has none.\n */\nexport function setUserEdit(service: object, edit: UserEdit | null): void {\n if (edit) {\n userEdits.set(service, edit);\n } else {\n userEdits.delete(service);\n }\n}\n\n/** The recorded edit when `inputValue` is the value it produced, else null. */\nexport function userEditFor(service: object, inputValue: string): UserEdit | null {\n const edit = userEdits.get(service);\n return edit?.value === inputValue ? edit : null;\n}\n","import { userEditFor } from '../caret/date-overflow';\nimport { MaskExpression } from '../ngx-mask-expression.enum';\nimport type { MaskHandlerFn } from './mask-handler.types';\n\n/** Punctuation the built-in email mask accepts besides `[a-zA-Z0-9]` (#1668). */\nconst EMAIL_AT = '@';\nconst EMAIL_LOCAL_PUNCTUATION = '._+-';\nconst EMAIL_DOMAIN_PUNCTUATION = '.-';\n\n/**\n * Whether `inputSymbol` is allowed email punctuation after `result` (the text accepted so far).\n * Punctuation cannot be the first character of the address, and '..' is blocked.\n */\nfunction isEmailPunctuation(inputSymbol: string, result: string): boolean {\n const allowed = result.includes(EMAIL_AT) ? EMAIL_DOMAIN_PUNCTUATION : EMAIL_LOCAL_PUNCTUATION;\n const last = result.slice(-1);\n return (\n allowed.includes(inputSymbol) &&\n last !== MaskExpression.EMPTY_STRING &&\n last !== EMAIL_AT &&\n !(inputSymbol === MaskExpression.DOT && last === MaskExpression.DOT)\n );\n}\n\n/**\n * Generic character-by-character pattern loop (moved verbatim from applyMask,\n * original lines 581-968). This is the default/fallback handler — always runs when\n * no exact/startsWith handler matched. IP and CPF_CNPJ pre-processors rewrite\n * `state.maskExpression` and then fall through into this loop.\n *\n * The inline HOURS/HOUR/MINUTE/SECOND/DAY/MONTH sub-branches (including the day-window\n * anchor flow-gating of #1611/#1513, CODEBASE_NOTES.md #20) are preserved unmodified —\n * they are explicitly out of scope for the phase-1 extraction boundary.\n *\n * Note: several branches read `this.maskExpression` (the instance field) rather than\n * the local `maskExpression` — this distinction is preserved exactly as in the\n * original source.\n */\nexport const genericPatternHandler: MaskHandlerFn = function (state, params) {\n const { inputArray } = params;\n const maskExpression = state.maskExpression;\n const processedValue = state.processedValue;\n let { cursor, result, multi, processedPosition, stepBack } = state;\n // The span of `inputValue` the user's last edit changed; a render of any other value changes none.\n const userEdit = userEditFor(this, params.inputValue);\n const prefixOffset =\n params.startsWithPrefix && !params.prefixAlreadyRemovedByCaller ? this.prefix.length : 0;\n\n for (\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n let i = 0, inputSymbol: string = inputArray[0]!;\n i < inputArray.length;\n i++, inputSymbol = inputArray[i] ?? MaskExpression.EMPTY_STRING\n ) {\n if (cursor === maskExpression.length) {\n break;\n }\n\n const symbolStarInPattern: boolean = MaskExpression.SYMBOL_STAR in this.patterns;\n if (\n this._checkSymbolMask(\n inputSymbol,\n maskExpression[cursor] ?? MaskExpression.EMPTY_STRING\n ) &&\n maskExpression[cursor + 1] === MaskExpression.SYMBOL_QUESTION\n ) {\n result += inputSymbol;\n cursor += 2;\n } else if (\n maskExpression[cursor + 1] === MaskExpression.SYMBOL_STAR &&\n multi &&\n this._checkSymbolMask(\n inputSymbol,\n maskExpression[cursor + 2] ?? MaskExpression.EMPTY_STRING\n )\n ) {\n result += inputSymbol;\n cursor += 3;\n multi = false;\n } else if (\n this._checkSymbolMask(\n inputSymbol,\n maskExpression[cursor] ?? MaskExpression.EMPTY_STRING\n ) &&\n maskExpression[cursor + 1] === MaskExpression.SYMBOL_STAR &&\n !symbolStarInPattern\n ) {\n result += inputSymbol;\n multi = true;\n } else if (\n maskExpression[cursor + 1] === MaskExpression.SYMBOL_QUESTION &&\n this._checkSymbolMask(\n inputSymbol,\n maskExpression[cursor + 2] ?? MaskExpression.EMPTY_STRING\n )\n ) {\n result += inputSymbol;\n cursor += 3;\n } else if (\n this._checkSymbolMask(\n inputSymbol,\n maskExpression[cursor] ?? MaskExpression.EMPTY_STRING\n )\n ) {\n // The two-digit hour pair read ahead: `24` (or `13` with apm) is padded to `02` / `01`\n // at its first digit, as a month `13` is, so the second digit starts the minutes.\n const hourOverflow =\n this.leadZeroDateTime &&\n (maskExpression[cursor] === MaskExpression.HOURS ||\n (maskExpression[cursor] === MaskExpression.HOUR &&\n maskExpression[cursor + 1] === MaskExpression.HOUR)) &&\n Number(inputSymbol + (inputArray[i + 1] ?? MaskExpression.EMPTY_STRING)) >\n (this.apm ? 12 : 23);\n if (\n hourOverflow ||\n (maskExpression[cursor] === MaskExpression.HOURS &&\n (this.apm ? Number(inputSymbol) > 9 : Number(inputSymbol) > 2))\n ) {\n processedPosition = !this.leadZeroDateTime\n ? processedPosition + 1\n : processedPosition;\n cursor += 1;\n this._shiftStep(cursor);\n i--;\n if (this.leadZeroDateTime) {\n result += '0';\n }\n continue;\n }\n if (maskExpression[cursor] === MaskExpression.HOUR) {\n // The hour digit before this one. `processedValue` is the raw input, so once a\n // leadZeroDateTime pad has put a `0` in front only `result` still lines up with the mask.\n const previousHourDigit = this.leadZeroDateTime\n ? result.slice(-1)\n : processedValue.slice(cursor - 1, cursor);\n if (\n this.apm\n ? (result.length === 1 && Number(result) > 1) ||\n (result === '1' && Number(inputSymbol) > 2) ||\n (previousHourDigit.length === 1 && Number(previousHourDigit) > 2) ||\n (previousHourDigit === '1' && Number(inputSymbol) > 2)\n : (result === '2' && Number(inputSymbol) > 3) ||\n ((result.slice(cursor - 2, cursor) === '2' ||\n result.slice(cursor - 3, cursor) === '2' ||\n result.slice(cursor - 4, cursor) === '2' ||\n result.slice(cursor - 1, cursor) === '2') &&\n Number(inputSymbol) > 3 &&\n cursor > 10)\n ) {\n processedPosition = processedPosition + 1;\n cursor += 1;\n i--;\n continue;\n }\n }\n if (\n maskExpression[cursor] === MaskExpression.MINUTE ||\n maskExpression[cursor] === MaskExpression.SECOND\n ) {\n if (Number(inputSymbol) > 5) {\n processedPosition = !this.leadZeroDateTime\n ? processedPosition + 1\n : processedPosition;\n cursor += 1;\n this._shiftStep(cursor);\n i--;\n if (this.leadZeroDateTime) {\n result += '0';\n }\n continue;\n }\n }\n // A `00` day, month or 12-hour hour that the user's edit just typed, pasted or\n // Backspaced into becomes `01` (leadZeroDateTime only). Programmatic writes and fields\n // the edit did not touch keep their `00`.\n if (\n userEdit &&\n this.leadZeroDateTime &&\n !this.keepCharacterPositions &&\n !this.writingValue &&\n inputSymbol === MaskExpression.NUMBER_ZERO &&\n result.slice(-1) === MaskExpression.NUMBER_ZERO &&\n i + prefixOffset >= userEdit.start &&\n i + prefixOffset <= userEdit.end &&\n (maskExpression[cursor - 1] === MaskExpression.DAY ||\n maskExpression[cursor - 1] === MaskExpression.MONTH ||\n (this.apm &&\n maskExpression[cursor] === MaskExpression.HOUR &&\n (maskExpression[cursor - 1] === MaskExpression.HOURS ||\n maskExpression[cursor - 1] === MaskExpression.HOUR)))\n ) {\n inputSymbol = '1';\n }\n const daysCount = 31;\n const inputValueCursor = processedValue[cursor] as string;\n const inputValueCursorPlusOne = processedValue[cursor + 1] as string;\n const inputValueCursorPlusTwo = processedValue[cursor + 2] as string;\n const inputValueCursorMinusOne = processedValue[cursor - 1] as string;\n const inputValueCursorMinusTwo = processedValue[cursor - 2] as string;\n const inputValueSliceMinusThreeMinusOne = processedValue.slice(cursor - 3, cursor - 1);\n const inputValueSliceMinusOnePlusOne = processedValue.slice(cursor - 1, cursor + 1);\n const inputValueSliceCursorPlusTwo = processedValue.slice(cursor, cursor + 2);\n const inputValueSliceMinusTwoCursor = processedValue.slice(cursor - 2, cursor);\n // Issue #1611: `cursor` indexes the mask, `i` indexes the input. On paste/writeValue\n // of a bare digit string the cursor runs ahead of the input by every emitted\n // separator, so cursor-based slices read the previous field's digits instead of the\n // day or month ('20231215' in '0000.M0.d0' read the day digits '21' as the month\n // window) — anchor the day/month window on the input index in those flows.\n // Keystroke flows keep the historical cursor anchor (with showMaskTyped the value\n // also carries placeholder chars, where the input anchor misreads).\n const windowStart = params.justPasted || this.writingValue ? i : cursor;\n const windowSlice = processedValue.slice(windowStart, windowStart + 2);\n const windowNext = processedValue[windowStart + 1] as string;\n // Issue #1523: when the date token directly abuts a plain digit\n // token (year-first masks without separators like 00M0d0 or\n // 0000M0d0), the backward-looking windows below read the previous\n // field's digits (year) as day/month digits and skip valid input.\n // Disable only those backward heuristics in that layout.\n const tokenAbutsDigitField = maskExpression[cursor - 1] === MaskExpression.NUMBER_ZERO;\n if (maskExpression[cursor] === MaskExpression.DAY) {\n const maskStartWithMonth = maskExpression.slice(0, 2) === MaskExpression.MONTHS;\n const startWithMonthInput: boolean =\n maskExpression.slice(0, 2) === MaskExpression.MONTHS &&\n this.specialCharacters.includes(inputValueCursorMinusTwo);\n if (\n (Number(inputSymbol) > 3 && this.leadZeroDateTime) ||\n (!maskStartWithMonth &&\n (Number(inputValueSliceCursorPlusTwo) > daysCount ||\n (!tokenAbutsDigitField &&\n Number(inputValueSliceMinusOnePlusOne) > daysCount) ||\n this.specialCharacters.includes(inputValueCursorPlusOne))) ||\n (startWithMonthInput\n ? Number(inputValueSliceMinusOnePlusOne) > daysCount ||\n (!this.specialCharacters.includes(inputValueCursor) &&\n this.specialCharacters.includes(inputValueCursorPlusTwo)) ||\n this.specialCharacters.includes(inputValueCursor)\n : Number(windowSlice) > daysCount ||\n (this.specialCharacters.includes(windowNext) && !params.backspaced))\n ) {\n processedPosition = !this.leadZeroDateTime\n ? processedPosition + 1\n : processedPosition;\n cursor += 1;\n this._shiftStep(cursor);\n i--;\n\n if (this.leadZeroDateTime) {\n result += '0';\n }\n continue;\n }\n }\n if (maskExpression[cursor] === MaskExpression.MONTH) {\n const monthsCount = 12;\n // Issue #1513: the backward-looking day/month windows below\n // assume the digits before the MONTH token belong to a DAY\n // field. In year-first masks with separators (e.g. 0000-M0-d0)\n // they read YEAR digits through the separator and shove a\n // spurious leading zero into the month. tokenAbutsDigitField\n // (#1523) only covers separator-less layouts, so derive field\n // ownership from the mask itself: locate the field (maximal\n // run of non-special tokens) immediately preceding this MONTH\n // token — a plain digit run of 3+ characters is a year, not a\n // day, and the day-based heuristics must not fire.\n let precedingFieldEnd = cursor - 1;\n while (\n precedingFieldEnd >= 0 &&\n this.specialCharacters.includes(maskExpression[precedingFieldEnd] as string)\n ) {\n precedingFieldEnd--;\n }\n let precedingFieldStart = precedingFieldEnd;\n while (\n precedingFieldStart >= 0 &&\n !this.specialCharacters.includes(maskExpression[precedingFieldStart] as string)\n ) {\n precedingFieldStart--;\n }\n const precedingField = maskExpression.slice(\n precedingFieldStart + 1,\n precedingFieldEnd + 1\n );\n const yearFieldPrecedesMonth =\n precedingField.length > 2 &&\n precedingField\n .split(MaskExpression.EMPTY_STRING)\n .every((token) => token === MaskExpression.NUMBER_ZERO);\n // mask without day\n const withoutDays: boolean =\n cursor === 0 &&\n (Number(inputSymbol) > 2 ||\n Number(inputValueSliceCursorPlusTwo) > monthsCount ||\n // after Backspace only a digit that follows the separator needs the pad\n // (`1/31` -> `01/31`); a lone `1` before placeholders stays as it is\n (this.specialCharacters.includes(inputValueCursorPlusOne) &&\n (!params.backspaced ||\n (this.leadZeroDateTime && /\\d/.test(inputValueCursorPlusTwo)))));\n // year-first masks (0000.M0.d0) switch the backward heuristics off: read the month's own\n // pair at the input index (the cursor anchor of `windowSlice` misreads a value that lacks\n // the separator before the month). A month digit that starts right after a separator and\n // is followed by one (`2020.1.31`, a replaced selection) is a lone digit, padded as well.\n const monthPair = processedValue.slice(i, i + 2);\n const yearFirstMonthOverflow =\n this.leadZeroDateTime &&\n yearFieldPrecedesMonth &&\n (Number(monthPair) > monthsCount ||\n (this.specialCharacters.includes(monthPair.charAt(1)) &&\n this.specialCharacters.includes(processedValue.charAt(i - 1))));\n // day<10 && month<12 for input\n const specialChart = maskExpression.slice(cursor + 2, cursor + 3);\n const day1monthInput: boolean =\n inputValueSliceMinusThreeMinusOne.includes(specialChart) &&\n maskExpression.includes('d0') &&\n ((this.specialCharacters.includes(inputValueCursorMinusTwo) &&\n Number(inputValueSliceMinusOnePlusOne) > monthsCount &&\n !this.specialCharacters.includes(inputValueCursor)) ||\n this.specialCharacters.includes(inputValueCursor));\n // month<12 && day<10 for input\n const day2monthInput: boolean =\n !tokenAbutsDigitField &&\n !yearFieldPrecedesMonth &&\n Number(inputValueSliceMinusThreeMinusOne) <= daysCount &&\n !this.specialCharacters.includes(inputValueSliceMinusThreeMinusOne as string) &&\n this.specialCharacters.includes(inputValueCursorMinusOne) &&\n (Number(inputValueSliceCursorPlusTwo) > monthsCount ||\n this.specialCharacters.includes(inputValueCursorPlusOne));\n // cursor === 5 && without days\n const day2monthInputDot: boolean =\n (Number(windowSlice) > monthsCount && cursor === 5) ||\n (this.specialCharacters.includes(windowNext) && cursor === 5);\n // // day<10 && month<12 for paste whole data\n const day1monthPaste: boolean =\n !tokenAbutsDigitField &&\n !yearFieldPrecedesMonth &&\n Number(inputValueSliceMinusThreeMinusOne) > daysCount &&\n !this.specialCharacters.includes(inputValueSliceMinusThreeMinusOne as string) &&\n !this.specialCharacters.includes(inputValueSliceMinusTwoCursor as string) &&\n Number(inputValueSliceMinusTwoCursor) > monthsCount &&\n maskExpression.includes('d0');\n // 10<day<31 && month<12 for paste whole data\n const day2monthPaste: boolean =\n !tokenAbutsDigitField &&\n !yearFieldPrecedesMonth &&\n Number(inputValueSliceMinusThreeMinusOne) <= daysCount &&\n !this.specialCharacters.includes(inputValueSliceMinusThreeMinusOne as string) &&\n !this.specialCharacters.includes(inputValueCursorMinusOne) &&\n Number(inputValueSliceMinusOnePlusOne) > monthsCount;\n if (\n (Number(inputSymbol) > 1 && this.leadZeroDateTime) ||\n withoutDays ||\n day1monthInput ||\n day2monthPaste ||\n day1monthPaste ||\n day2monthInput ||\n (day2monthInputDot && !this.leadZeroDateTime) ||\n yearFirstMonthOverflow\n ) {\n processedPosition = !this.leadZeroDateTime\n ? processedPosition + 1\n : processedPosition;\n cursor += 1;\n this._shiftStep(cursor);\n i--;\n if (this.leadZeroDateTime) {\n result += '0';\n }\n continue;\n }\n }\n result += inputSymbol;\n cursor++;\n } else if (\n this.specialCharacters.includes(inputSymbol) &&\n maskExpression[cursor] === inputSymbol\n ) {\n result += inputSymbol;\n cursor++;\n } else if (\n this.specialCharacters.indexOf(\n maskExpression[cursor] ?? MaskExpression.EMPTY_STRING\n ) !== -1\n ) {\n result += maskExpression[cursor];\n cursor++;\n this._shiftStep(cursor);\n i--;\n } else if (maskExpression[cursor] === MaskExpression.NUMBER_NINE && this.showMaskTyped) {\n this._shiftStep(cursor);\n } else if (\n this.patterns[maskExpression[cursor] ?? MaskExpression.EMPTY_STRING] &&\n this.patterns[maskExpression[cursor] ?? MaskExpression.EMPTY_STRING]?.optional\n ) {\n // If the input symbol is whitespace or doesn't match the pattern,\n // skip it without consuming the mask position\n if (inputSymbol.trim() === MaskExpression.EMPTY_STRING) {\n // Skip whitespace input, don't advance mask cursor\n continue;\n }\n if (\n !!inputArray[cursor] &&\n maskExpression !== '099.099.099.099' &&\n maskExpression !== '000.000.000-00' &&\n maskExpression !== '00.000.000/0000-00' &&\n !maskExpression.match(/^9+\\.0+$/) &&\n !this.patterns[maskExpression[cursor] ?? MaskExpression.EMPTY_STRING]?.optional\n ) {\n result += inputArray[cursor];\n }\n if (\n maskExpression.includes(MaskExpression.NUMBER_NINE + MaskExpression.SYMBOL_STAR) &&\n maskExpression.includes(MaskExpression.NUMBER_ZERO + MaskExpression.SYMBOL_STAR)\n ) {\n cursor++;\n }\n\n cursor++;\n i--;\n } else if (\n this.maskExpression[cursor + 1] === MaskExpression.SYMBOL_STAR &&\n // A typed char that exactly matches the mask's literal char at cursor+2\n // (e.g. the '@' in 'A*@A*.A*') always terminates the 'A*' run, regardless\n // of whether that literal is registered in `specialCharacters` — an\n // explicitly empty `specialCharacters` list must not make mask literals\n // unmatchable (#1512).\n (this._findSpecialChar(this.maskExpression[cursor + 2] ?? MaskExpression.EMPTY_STRING)\n ? this._findSpecialChar(inputSymbol) === this.maskExpression[cursor + 2]\n : inputSymbol === this.maskExpression[cursor + 2]) &&\n multi\n ) {\n cursor += 3;\n result += inputSymbol;\n } else if (\n this.maskExpression[cursor + 1] === MaskExpression.SYMBOL_QUESTION &&\n (this._findSpecialChar(this.maskExpression[cursor + 2] ?? MaskExpression.EMPTY_STRING)\n ? this._findSpecialChar(inputSymbol) === this.maskExpression[cursor + 2]\n : inputSymbol === this.maskExpression[cursor + 2]) &&\n multi\n ) {\n cursor += 3;\n result += inputSymbol;\n } else if (\n maskExpression === MaskExpression.EMAIL_MASK &&\n isEmailPunctuation(inputSymbol, result)\n ) {\n // #1668: 'A' only matches [a-zA-Z0-9], so the punctuation real addresses carry\n // would be dropped. Keep it inside the current 'A*' run (cursor is unchanged).\n result += inputSymbol;\n } else if (\n this.showMaskTyped &&\n this.specialCharacters.indexOf(inputSymbol) < 0 &&\n inputSymbol !== this.placeHolderCharacter &&\n this.placeHolderCharacter.length === 1\n ) {\n stepBack = true;\n }\n }\n\n state.cursor = cursor;\n state.result = result;\n state.multi = multi;\n state.processedPosition = processedPosition;\n state.stepBack = stepBack;\n return state;\n};\n","import { MaskExpression } from '../ngx-mask-expression.enum';\nimport type { MaskHandlerFn } from './mask-handler.types';\n\n/** IP pre-processor (moved verbatim from applyMask). Sets `this.ipError`, rewrites\n * the mask to `099.099.099.099`, then falls through to the generic loop. */\nexport const ipHandler: MaskHandlerFn = function (state) {\n const valuesIP = state.processedValue.split(MaskExpression.DOT);\n this.ipError = this._validIP(valuesIP);\n\n state.maskExpression = '099.099.099.099';\n return state;\n};\n","import { MaskExpression } from '../ngx-mask-expression.enum';\nimport type { MaskHandlerFn } from './mask-handler.types';\n\n/** PERCENT handler (moved verbatim from applyMask). startsWith(PERCENT); terminal —\n * produces the final `result`, no fallthrough. */\nexport const percentHandler: MaskHandlerFn = function (state, params) {\n const { backspaced } = params;\n const { cursor } = state;\n let processedValue = state.processedValue;\n if (\n processedValue.match('[a-z]|[A-Z]') ||\n // eslint-disable-next-line no-useless-escape\n (processedValue.match(/[-!$%^&*()_+|~=`{}\\[\\]:\";'<>?,\\/.]/) && !backspaced)\n ) {\n processedValue = this._stripToDecimal(processedValue);\n const precision: number = this.getPrecision(state.maskExpression);\n\n processedValue = this.checkInputPrecision(processedValue, precision);\n }\n const decimalMarker = this._activeDecimalMarker(processedValue);\n if (\n processedValue.indexOf(decimalMarker) > 0 &&\n !this.percentage(processedValue.substring(0, processedValue.indexOf(decimalMarker)))\n ) {\n let base: string = processedValue.substring(0, processedValue.indexOf(decimalMarker) - 1);\n if (\n this.allowNegativeNumbers &&\n processedValue.slice(cursor, cursor + 1) === MaskExpression.MINUS &&\n !backspaced\n ) {\n base = processedValue.substring(0, processedValue.indexOf(decimalMarker));\n }\n\n processedValue = `${base}${processedValue.substring(\n processedValue.indexOf(decimalMarker),\n processedValue.length\n )}`;\n }\n let value: string;\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n this.allowNegativeNumbers && processedValue.slice(cursor, cursor + 1) === MaskExpression.MINUS\n ? (value = `${MaskExpression.MINUS}${processedValue.slice(cursor + 1, cursor + processedValue.length)}`)\n : (value = processedValue);\n if (this.percentage(value)) {\n state.result = this._splitPercentZero(processedValue);\n } else {\n state.result = this._splitPercentZero(\n processedValue.substring(0, processedValue.length - 1)\n );\n }\n state.processedValue = processedValue;\n return state;\n};\n","import { MaskExpression } from '../ngx-mask-expression.enum';\nimport { escapeRegExp } from '../ngx-mask.utils';\nimport type { MaskHandlerFn } from './mask-handler.types';\n\n/** Characters rejected while typing a separator mask (' ' stands for any whitespace). */\nconst INVALID_SEPARATOR_CHARS = [...'@#!$%^&*()_+|~=`{}[]: ,.\";<>?/'];\n\n/**\n * SEPARATOR handler (moved verbatim from applyMask, original lines 219-580).\n * Discriminator: `maskExpression.startsWith(MaskExpression.SEPARATOR)`. Produces the\n * final `result` for this call.\n *\n * Two sequential zero-handling stages are preserved together, in original relative\n * order (CODEBASE_NOTES.md #13): the `if (backspaced)` guard block and the\n * precision-0 leading-zero stripper.\n *\n * The `typeFromDecimals` sub-case (#733/#1414/#1315) early-returns the final string\n * via `state.earlyReturn` after calling `cb()` — this must bypass the shared\n * post-processing in `applyMask` exactly, or the caret-pin `cb()` contract breaks.\n */\nexport const separatorHandler: MaskHandlerFn = function (state, params) {\n const {\n backspaced,\n justPasted,\n startsWithPrefix,\n prefixAlreadyRemovedByCaller,\n cb,\n inputValue,\n } = params;\n let { processedValue, processedPosition, backspaceShift, shift, stepBack } = state;\n let result: string;\n\n if (\n processedValue.match('[wа-яА-Я]') ||\n processedValue.match('[ЁёА-я]') ||\n processedValue.match('[a-z]|[A-Z]') ||\n processedValue.match(/[-@#!$%\\\\^&*()_£¬'+|~=`{}\\]:\";<>.?/]/) ||\n processedValue.match('[^A-Za-z0-9,]')\n ) {\n processedValue = this._stripToDecimal(processedValue);\n }\n\n const precision: number = this.getPrecision(state.maskExpression);\n let decimalMarker = this.decimalMarker;\n\n if (Array.isArray(this.decimalMarker)) {\n decimalMarker = this._activeDecimalMarker(this.actualValue);\n }\n\n // Issues #733/#1414/#1315: opt-in \"banking\" typing mode — typed digits fill\n // the value from the decimal end, ATM/calculator style (5 -> 0.05 -> 0.57\n // -> 5.73); backspace shifts digits back to the right. Only keystroke and\n // backspace flows are reinterpreted; paste and writeValue keep the regular\n // separator formatting. The early return leaves every existing separator\n // path byte-identical when the option is off.\n if (\n this.typeFromDecimals &&\n Number.isFinite(precision) &&\n precision > 0 &&\n !justPasted &&\n !this.writingValue\n ) {\n result = this._formatFromDecimals(processedValue, precision, decimalMarker as string);\n this._shift.clear();\n const res =\n result.includes(MaskExpression.MINUS) && this.prefix && this.allowNegativeNumbers\n ? `${MaskExpression.MINUS}${this.prefix}${result\n .split(MaskExpression.MINUS)\n .join(MaskExpression.EMPTY_STRING)}${this.suffix}`\n : result.length\n ? `${this.prefix}${result}${this.suffix}`\n : this.instantPrefix\n ? this.prefix\n : MaskExpression.EMPTY_STRING;\n // Pin the caret to the end of the value part: every keystroke reshapes\n // the whole string, so the in-place caret position is meaningless here.\n cb(res.length - this.suffix.length - processedPosition, true);\n state.earlyReturn = res;\n return state;\n }\n\n // Issue #1250: typing an additional decimal marker into a value that\n // already contains one must be a no-op — otherwise everything after the\n // new marker is re-parsed as a fresh decimal part and the value is\n // mangled (15.000,53 + ',' typed after the '1' -> 1,5). Remove the newly\n // typed marker (the char right before the caret) and step the caret back.\n // Paste keeps its own semantics (#1547 below: last marker wins), and\n // backspace/writeValue flows cannot introduce a new marker.\n if (!justPasted && !backspaced && !this.writingValue) {\n const isDecimalMarkerChar = (char: string | undefined): boolean =>\n !!char &&\n char !== this.thousandSeparator &&\n (Array.isArray(this.decimalMarker)\n ? this.decimalMarker.includes(char as MaskExpression.COMMA | MaskExpression.DOT)\n : char === this.decimalMarker);\n const prefixOffset =\n startsWithPrefix && !prefixAlreadyRemovedByCaller ? this.prefix.length : 0;\n const typedMarkerIndex = processedPosition - prefixOffset - 1;\n if (typedMarkerIndex >= 0 && isDecimalMarkerChar(processedValue[typedMarkerIndex])) {\n let markerCount = 0;\n for (const char of processedValue) {\n if (isDecimalMarkerChar(char)) {\n markerCount++;\n }\n }\n if (markerCount > 1) {\n processedValue =\n processedValue.slice(0, typedMarkerIndex) +\n processedValue.slice(typedMarkerIndex + 1);\n stepBack = true;\n }\n }\n }\n\n // Issue #1547: a pasted value may contain grouping separators that are\n // also configured decimal markers (default decimalMarker is ['.', ',']),\n // e.g. '1,234.56'. Only the last marker character can actually be the\n // decimal marker — treat the earlier ones as thousand separators and\n // strip them, otherwise formatting cuts the value off at the first one.\n if (justPasted && Array.isArray(this.decimalMarker)) {\n const markerPositions: number[] = [];\n for (let i = 0; i < processedValue.length; i++) {\n const char = processedValue[i] as string;\n if (\n char !== this.thousandSeparator &&\n this.decimalMarker.includes(char as MaskExpression.COMMA | MaskExpression.DOT)\n ) {\n markerPositions.push(i);\n }\n }\n if (markerPositions.length > 1) {\n const lastMarkerPosition = markerPositions[markerPositions.length - 1];\n processedValue = processedValue\n .split(MaskExpression.EMPTY_STRING)\n .filter(\n (_, index) => index === lastMarkerPosition || !markerPositions.includes(index)\n )\n .join(MaskExpression.EMPTY_STRING);\n }\n }\n\n if (backspaced) {\n const { decimalMarkerIndex, nonZeroIndex } = this._findFirstNonZeroAndDecimalIndex(\n processedValue,\n decimalMarker as '.' | ','\n );\n const zeroIndexMinus = processedValue[0] === MaskExpression.MINUS;\n const zeroIndexDecimalMarker = processedValue[0] === decimalMarker;\n const firstIndexDecimalMarker = processedValue[1] === decimalMarker;\n\n // Issues #1355/#1578: an all-zero remainder (e.g. '00' from '500', '00,000'\n // from '100,000') must keep its zeros, matching the ',000,000' case.\n // Only collapse when nothing but a bare decimal marker (or '-.') remains.\n if (\n (zeroIndexDecimalMarker && !nonZeroIndex) ||\n (zeroIndexMinus && firstIndexDecimalMarker && !nonZeroIndex)\n ) {\n processedValue = MaskExpression.NUMBER_ZERO;\n }\n\n if (decimalMarkerIndex && nonZeroIndex && zeroIndexMinus && processedPosition === 1) {\n if (decimalMarkerIndex < nonZeroIndex || decimalMarkerIndex > nonZeroIndex) {\n processedValue = MaskExpression.MINUS + processedValue.slice(nonZeroIndex);\n }\n }\n\n // Issue #1516: decimalMarkerIndex is 0 when the remainder starts with\n // the decimal marker (',34' after deleting the integer part) — a truthy\n // check would treat it as \"no decimal marker\" and slice the marker off.\n if (decimalMarkerIndex === null && nonZeroIndex && processedValue.length > nonZeroIndex) {\n processedValue = zeroIndexMinus\n ? MaskExpression.MINUS + processedValue.slice(nonZeroIndex)\n : processedValue.slice(nonZeroIndex);\n }\n\n if (decimalMarkerIndex && nonZeroIndex && processedPosition === 0) {\n if (decimalMarkerIndex < nonZeroIndex) {\n processedValue = processedValue.slice(decimalMarkerIndex - 1);\n }\n if (decimalMarkerIndex > nonZeroIndex) {\n processedValue = processedValue.slice(nonZeroIndex);\n }\n }\n }\n\n // Leading-zero stripping is a typing-time rule ('05' -> '5'). When backspaced,\n // leading zeros before a non-zero digit were already removed above, and an\n // all-zero remainder must keep its zeros (issues #1355/#1578).\n if (precision === 0 && !backspaced) {\n processedValue = this.allowNegativeNumbers\n ? processedValue.length > 2 &&\n processedValue[0] === MaskExpression.MINUS &&\n processedValue[1] === MaskExpression.NUMBER_ZERO &&\n processedValue[2] !== this.thousandSeparator &&\n processedValue[2] !== MaskExpression.COMMA &&\n processedValue[2] !== MaskExpression.DOT\n ? '-' + processedValue.slice(2, processedValue.length)\n : processedValue[0] === MaskExpression.NUMBER_ZERO &&\n processedValue.length > 1 &&\n processedValue[1] !== this.thousandSeparator &&\n processedValue[1] !== MaskExpression.COMMA &&\n processedValue[1] !== MaskExpression.DOT\n ? processedValue.slice(1, processedValue.length)\n : processedValue\n : processedValue.length > 1 &&\n processedValue[0] === MaskExpression.NUMBER_ZERO &&\n processedValue[1] !== this.thousandSeparator &&\n processedValue[1] !== MaskExpression.COMMA &&\n processedValue[1] !== MaskExpression.DOT\n ? processedValue.slice(1, processedValue.length)\n : processedValue;\n } else {\n if (processedValue[0] === decimalMarker && processedValue.length > 1 && !backspaced) {\n processedValue =\n MaskExpression.NUMBER_ZERO + processedValue.slice(0, processedValue.length + 1);\n this.plusOnePosition = true;\n }\n if (\n processedValue[0] === MaskExpression.NUMBER_ZERO &&\n processedValue[1] !== decimalMarker &&\n processedValue[1] !== this.thousandSeparator &&\n !backspaced\n ) {\n processedValue =\n processedValue.length > 1\n ? processedValue.slice(0, 1) +\n decimalMarker +\n processedValue.slice(1, processedValue.length + 1)\n : processedValue;\n this.plusOnePosition = true;\n }\n if (\n this.allowNegativeNumbers &&\n !backspaced &&\n processedValue[0] === MaskExpression.MINUS &&\n (processedValue[1] === decimalMarker ||\n processedValue[1] === MaskExpression.NUMBER_ZERO)\n ) {\n processedValue =\n processedValue[1] === decimalMarker && processedValue.length > 2\n ? processedValue.slice(0, 1) +\n MaskExpression.NUMBER_ZERO +\n processedValue.slice(1, processedValue.length)\n : processedValue[1] === MaskExpression.NUMBER_ZERO &&\n processedValue.length > 2 &&\n processedValue[2] !== decimalMarker\n ? processedValue.slice(0, 2) +\n decimalMarker +\n processedValue.slice(2, processedValue.length)\n : processedValue;\n this.plusOnePosition = true;\n }\n }\n\n // Historical note: pre-refactor code used different allowed-character regexes\n // per config (plain separator: no COMMA; dot thousand-sep: no SPACE, COMMA OK;\n // comma thousand-sep: no SPACE, COMMA OK). The unified regex below removes\n // exactly the active thousandSeparator + decimalMarker(s) from the invalid set,\n // so each config already accepts its own chars and rejects the others —\n // verified by the \"unified invalidChars regex\" cases in separator.spec.ts.\n const thousandSeparatorCharEscaped: string = this._charToRegExpExpression(\n this.thousandSeparator\n );\n const allowedChars = [this.thousandSeparator, ...[this.decimalMarker].flat()];\n const invalidChars = INVALID_SEPARATOR_CHARS.filter((char) => !allowedChars.includes(char))\n .map((char) => (char === ' ' ? '\\\\s' : escapeRegExp(char)))\n .join('');\n\n const invalidCharRegexp = new RegExp('[' + invalidChars + ']');\n if (processedValue.match(invalidCharRegexp)) {\n processedValue = processedValue.substring(0, processedValue.length - 1);\n }\n\n processedValue = this.checkInputPrecision(processedValue, precision);\n const strForSep: string = processedValue.replace(\n new RegExp(thousandSeparatorCharEscaped, 'g'),\n ''\n );\n\n result = this._formatWithSeparators(\n strForSep,\n this.thousandSeparator,\n this.decimalMarker,\n precision\n );\n\n const commaShift: number =\n result.indexOf(MaskExpression.COMMA) - processedValue.indexOf(MaskExpression.COMMA);\n const shiftStep: number = result.length - processedValue.length;\n const backspacedDecimalMarkerWithSeparatorLimit =\n backspaced && result.length < inputValue.length - this.suffix.length && this.separatorLimit;\n\n if (\n (result[processedPosition - 1] === this.thousandSeparator ||\n result[processedPosition - this.prefix.length]) &&\n this.prefix &&\n backspaced\n ) {\n processedPosition = processedPosition - 1;\n } else if (\n (shiftStep > 0 && result[processedPosition] !== this.thousandSeparator) ||\n backspacedDecimalMarkerWithSeparatorLimit\n ) {\n backspaceShift = true;\n let _shift = 0;\n do {\n this._shift.add(processedPosition + _shift);\n _shift++;\n } while (_shift < shiftStep);\n } else if (\n result[processedPosition - 1] === this.thousandSeparator ||\n shiftStep === -4 ||\n shiftStep === -3 ||\n result[processedPosition] === this.thousandSeparator\n ) {\n this._shift.clear();\n this._shift.add(processedPosition - 1);\n } else if (\n (commaShift !== 0 &&\n processedPosition > 0 &&\n !(\n result.indexOf(MaskExpression.COMMA) >= processedPosition && processedPosition > 3\n )) ||\n (!(result.indexOf(MaskExpression.DOT) >= processedPosition && processedPosition > 3) &&\n shiftStep <= 0)\n ) {\n this._shift.clear();\n backspaceShift = true;\n shift = shiftStep;\n\n processedPosition += shiftStep;\n this._shift.add(processedPosition);\n } else {\n this._shift.clear();\n }\n\n state.processedValue = processedValue;\n state.processedPosition = processedPosition;\n state.result = result;\n state.backspaceShift = backspaceShift;\n state.shift = shift;\n state.stepBack = stepBack;\n return state;\n};\n","import { MaskExpression } from '../ngx-mask-expression.enum';\nimport type { NgxMaskApplierService } from '../ngx-mask-applier.service';\nimport { cpfCnpjHandler } from './cpf-cnpj.handler';\nimport { genericPatternHandler } from './generic-pattern.handler';\nimport { ipHandler } from './ip.handler';\nimport type { MaskHandlerEntry, MaskHandlerParams, MaskHandlerState } from './mask-handler.types';\nimport { percentHandler } from './percent.handler';\nimport { separatorHandler } from './separator.handler';\n\n/** Ordered dispatch table. Exact-match entries (IP, CPF_CNPJ) MUST precede\n * startsWith entries (PERCENT, SEPARATOR) — mirrors the original `if/else if` order\n * and preserves the exact-before-substring guarantee (CODEBASE_NOTES #3/#4).\n * `terminal: false` = pre-processor (rewrites mask, falls through to generic loop);\n * `terminal: true` = resolves `result` and skips the generic loop. */\ntype RegistryEntry = MaskHandlerEntry & {\n readonly terminal: boolean;\n};\n\nconst MASK_HANDLERS: readonly RegistryEntry[] = [\n {\n id: 'ip',\n terminal: false,\n match: (maskExpression) => maskExpression === MaskExpression.IP,\n handle: ipHandler,\n },\n {\n id: 'cpf-cnpj',\n terminal: false,\n match: (maskExpression) =>\n maskExpression === MaskExpression.CPF_CNPJ ||\n maskExpression === MaskExpression.CPF_CNPJ_ALPHA,\n handle: cpfCnpjHandler,\n },\n {\n id: 'percent',\n terminal: true,\n match: (maskExpression) => maskExpression.startsWith(MaskExpression.PERCENT),\n handle: percentHandler,\n },\n {\n id: 'separator',\n terminal: true,\n match: (maskExpression) => maskExpression.startsWith(MaskExpression.SEPARATOR),\n handle: separatorHandler,\n },\n];\n\n/** Runs mask-type dispatch: first matching entry wins. IP/CPF_CNPJ pre-process then\n * fall through to the generic loop; PERCENT/SEPARATOR resolve terminally; no match →\n * generic loop directly (the original `else`). IP and CPF_CNPJ are mutually exclusive\n * exact matches, so scanning the ordered table is behavior-identical to the original\n * IP → CPF_CNPJ → PERCENT → SEPARATOR → else chain. */\nexport function dispatchMaskHandler(\n self: NgxMaskApplierService,\n state: MaskHandlerState,\n params: MaskHandlerParams\n): MaskHandlerState {\n for (const entry of MASK_HANDLERS) {\n if (entry.match(state.maskExpression)) {\n const next = entry.handle.call(self, state, params);\n return entry.terminal ? next : genericPatternHandler.call(self, next, params);\n }\n }\n return genericPatternHandler.call(self, state, params);\n}\n","import { inject, Injectable } from '@angular/core';\nimport type { DecimalMarkerChar, NgxMaskConfig } from './ngx-mask.config';\nimport { NGX_MASK_CONFIG } from './ngx-mask.config';\nimport { MaskExpression } from './ngx-mask-expression.enum';\nimport {\n activeDecimalMarker,\n digitsOf,\n escapeRegExp,\n ignoreDigitSeparator,\n nextFillableIndex,\n} from './ngx-mask.utils';\nimport { dispatchMaskHandler } from './mask-handlers/mask-handlers.registry';\nimport type { MaskHandlerState } from './mask-handlers/mask-handler.types';\n\n@Injectable()\nexport class NgxMaskApplierService {\n protected _config = inject<NgxMaskConfig>(NGX_MASK_CONFIG);\n\n public dropSpecialCharacters: NgxMaskConfig['dropSpecialCharacters'] =\n this._config.dropSpecialCharacters;\n\n public hiddenInput: NgxMaskConfig['hiddenInput'] = this._config.hiddenInput;\n\n public clearIfNotMatch: NgxMaskConfig['clearIfNotMatch'] = this._config.clearIfNotMatch;\n\n public specialCharacters: NgxMaskConfig['specialCharacters'] = this._config.specialCharacters;\n\n public patterns: NgxMaskConfig['patterns'] = this._config.patterns;\n\n public prefix: NgxMaskConfig['prefix'] = this._config.prefix;\n\n public suffix: NgxMaskConfig['suffix'] = this._config.suffix;\n\n private _thousandSeparator = ignoreDigitSeparator(this._config.thousandSeparator);\n\n /**\n * The separator between thousand groups. One containing a digit is ignored entirely (no\n * grouping, nothing stripped): it could not be told from the number's own digits, and grouping\n * with it would re-match its own output forever.\n */\n public get thousandSeparator(): NgxMaskConfig['thousandSeparator'] {\n return this._thousandSeparator;\n }\n\n public set thousandSeparator(value: NgxMaskConfig['thousandSeparator']) {\n this._thousandSeparator = ignoreDigitSeparator(value);\n }\n\n public decimalMarker: NgxMaskConfig['decimalMarker'] = this._config.decimalMarker;\n\n public showMaskTyped: NgxMaskConfig['showMaskTyped'] = this._config.showMaskTyped;\n\n public placeHolderCharacter: NgxMaskConfig['placeHolderCharacter'] =\n this._config.placeHolderCharacter;\n\n public validation: NgxMaskConfig['validation'] = this._config.validation;\n\n public separatorLimit: NgxMaskConfig['separatorLimit'] = this._config.separatorLimit;\n\n public allowNegativeNumbers: NgxMaskConfig['allowNegativeNumbers'] =\n this._config.allowNegativeNumbers;\n\n public leadZeroDateTime: NgxMaskConfig['leadZeroDateTime'] = this._config.leadZeroDateTime;\n\n public leadZero: NgxMaskConfig['leadZero'] = this._config.leadZero;\n\n public typeFromDecimals: NgxMaskConfig['typeFromDecimals'] = this._config.typeFromDecimals;\n\n public apm: NgxMaskConfig['apm'] = this._config.apm;\n\n public inputTransformFn: NgxMaskConfig['inputTransformFn'] | null =\n this._config.inputTransformFn;\n\n public outputTransformFn: NgxMaskConfig['outputTransformFn'] | null =\n this._config.outputTransformFn;\n\n public keepCharacterPositions: NgxMaskConfig['keepCharacterPositions'] =\n this._config.keepCharacterPositions;\n\n public instantPrefix: NgxMaskConfig['instantPrefix'] = this._config.instantPrefix;\n\n public triggerOnMaskChange: NgxMaskConfig['triggerOnMaskChange'] =\n this._config.triggerOnMaskChange;\n\n protected _shift = new Set<number>();\n\n public plusOnePosition = false;\n\n public maskExpression = '';\n\n public actualValue = '';\n\n public shownMaskExpression: NgxMaskConfig['shownMaskExpression'] =\n this._config.shownMaskExpression;\n\n public deletedSpecialCharacter = false;\n\n /**\n * Whether we are currently in writeValue function, in this case when applying the mask we don't want to trigger onChange function,\n * since writeValue should be a one way only process of writing the DOM value based on the Angular model value.\n */\n public writingValue = false;\n\n public ipError?: boolean;\n\n public cpfCnpjError?: boolean;\n\n public applyMask(\n inputValue: string | object | boolean | null | undefined,\n maskExpression: string,\n position = 0,\n justPasted = false,\n backspaced = false,\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n cb: (actualShift: number, backspaceShift: boolean) => void = () => {}\n ): string {\n if (!maskExpression || typeof inputValue !== 'string') {\n return MaskExpression.EMPTY_STRING;\n }\n let cursor = 0;\n let result = '';\n const multi = false;\n let backspaceShift = false;\n let shift = 1;\n let stepBack = false;\n let processedValue = inputValue;\n let processedPosition = position;\n\n const startsWithPrefix = processedValue.slice(0, this.prefix.length) === this.prefix;\n // On paste with showMaskTyped, NgxMaskService.applyMask has already removed the\n // prefix via removeMask() before delegating here (unless the value consisted of\n // the prefix alone, in which case the raw value falls through). Stripping again\n // would eat leading characters that merely look like the prefix (#1551).\n const prefixAlreadyRemovedByCaller =\n justPasted &&\n this.showMaskTyped &&\n this.placeHolderCharacter.length === 1 &&\n !this.leadZeroDateTime &&\n processedValue !== this.prefix;\n\n if (startsWithPrefix && !prefixAlreadyRemovedByCaller) {\n processedValue = processedValue.slice(this.prefix.length);\n }\n if (!!this.suffix && processedValue.length > 0) {\n processedValue = this.checkAndRemoveSuffix(processedValue);\n }\n if (processedValue === '(' && this.prefix) {\n processedValue = '';\n }\n const inputArray: string[] = processedValue.toString().split(MaskExpression.EMPTY_STRING);\n if (\n this.allowNegativeNumbers &&\n processedValue.slice(cursor, cursor + 1) === MaskExpression.MINUS\n ) {\n result += processedValue.slice(cursor, cursor + 1);\n }\n const arr = digitsOf(processedValue);\n\n // Per-mask-type dispatch (IP/CPF_CNPJ pre-processors → generic loop; PERCENT and\n // SEPARATOR terminal handlers; generic pattern loop as fallback). See\n // ./mask-handlers/mask-handlers.registry.ts.\n const state: MaskHandlerState = {\n processedValue,\n processedPosition,\n cursor,\n result,\n multi,\n backspaceShift,\n shift,\n stepBack,\n maskExpression,\n };\n const resolved = dispatchMaskHandler(this, state, {\n inputValue,\n position,\n justPasted,\n backspaced,\n cb,\n inputArray,\n arr,\n startsWithPrefix,\n prefixAlreadyRemovedByCaller,\n });\n if (typeof resolved.earlyReturn === 'string') {\n return resolved.earlyReturn;\n }\n processedValue = resolved.processedValue;\n processedPosition = resolved.processedPosition;\n cursor = resolved.cursor;\n result = resolved.result;\n backspaceShift = resolved.backspaceShift;\n shift = resolved.shift;\n stepBack = resolved.stepBack;\n // eslint-disable-next-line no-param-reassign\n maskExpression = resolved.maskExpression;\n if (\n result[processedPosition - 1] &&\n result.length + 1 === maskExpression.length &&\n this.specialCharacters.indexOf(\n maskExpression[maskExpression.length - 1] ?? MaskExpression.EMPTY_STRING\n ) !== -1\n ) {\n result += maskExpression[maskExpression.length - 1];\n }\n let newPosition: number = processedPosition + 1;\n\n while (this._shift.has(newPosition)) {\n shift++;\n newPosition++;\n }\n\n let actualShift: number =\n justPasted && !maskExpression.startsWith(MaskExpression.SEPARATOR)\n ? cursor\n : this._shift.has(processedPosition)\n ? shift\n : 0;\n if (stepBack) {\n actualShift--;\n }\n\n cb(actualShift, backspaceShift);\n if (shift < 0) {\n this._shift.clear();\n }\n let onlySpecial = false;\n if (backspaced) {\n onlySpecial = inputArray.every((char) => this.specialCharacters.includes(char));\n }\n\n let res = `${this.prefix}${onlySpecial ? MaskExpression.EMPTY_STRING : result}${\n this.showMaskTyped ? '' : this.suffix\n }`;\n\n if (result.length === 0) {\n res = this.instantPrefix ? `${this.prefix}${result}` : `${result}`;\n }\n\n const isSpecialCharacterMaskFirstSymbol =\n processedValue.length === 1 &&\n this.specialCharacters.includes(maskExpression[0] as string) &&\n processedValue !== maskExpression[0];\n\n if (isSpecialCharacterMaskFirstSymbol) {\n // The mask may start with several literal special characters in a row\n // (e.g. '+(000) 000-0000'). A single typed character must be checked\n // against the first PATTERN position of the mask, not literally against\n // index 1 — otherwise a valid digit is rejected and the leading literals\n // are never auto-filled (#1498).\n const firstPatternIndex = nextFillableIndex(maskExpression, this.specialCharacters, 1);\n if (\n !this._checkSymbolMask(\n processedValue,\n maskExpression[firstPatternIndex] ?? MaskExpression.EMPTY_STRING\n )\n ) {\n return '';\n }\n }\n\n if (result.includes(MaskExpression.MINUS) && this.prefix && this.allowNegativeNumbers) {\n if (backspaced && result === MaskExpression.MINUS) {\n return '';\n }\n res = `${MaskExpression.MINUS}${this.prefix}${result\n .split(MaskExpression.MINUS)\n .join(MaskExpression.EMPTY_STRING)}${this.suffix}`;\n }\n return res;\n }\n\n public _findDropSpecialChar(inputSymbol: string): undefined | string {\n if (Array.isArray(this.dropSpecialCharacters)) {\n return this.dropSpecialCharacters.find((val: string) => val === inputSymbol);\n }\n return this._findSpecialChar(inputSymbol);\n }\n\n public _findSpecialChar(inputSymbol: string): undefined | string {\n return this.specialCharacters.find((val: string) => val === inputSymbol);\n }\n\n public _checkSymbolMask(inputSymbol: string, maskSymbol: string): boolean {\n const pattern = this.patterns[maskSymbol]?.pattern;\n return pattern ? this._testPattern(pattern, inputSymbol) : false;\n }\n\n /**\n * `RegExp.prototype.test` is stateful for patterns carrying the `g` or `y` flag (it starts\n * at `lastIndex`), so a user pattern such as `/[0-9]/g` would alternate between accepting\n * and rejecting identical input. Every pattern test goes through here to start from 0.\n */\n protected _testPattern(pattern: RegExp, value: string): boolean {\n pattern.lastIndex = 0;\n return pattern.test(value);\n }\n\n protected _formatWithSeparators = (\n str: string,\n thousandSeparatorChar: string,\n decimalChars: string | string[],\n precision: number\n ) => {\n let x: string[];\n let decimalChar: string;\n\n if (Array.isArray(decimalChars)) {\n const regExp = new RegExp(decimalChars.map((v) => escapeRegExp(v)).join('|'));\n x = str.split(regExp);\n decimalChar = str.match(regExp)?.[0] ?? MaskExpression.EMPTY_STRING;\n } else {\n x = str.split(decimalChars);\n decimalChar = decimalChars;\n }\n const decimals: string =\n x.length > 1 ? `${decimalChar}${x[1]}` : MaskExpression.EMPTY_STRING;\n let res: string = x[0] ?? MaskExpression.EMPTY_STRING;\n const separatorLimit: string = this.separatorLimit.replace(\n /\\s/g,\n MaskExpression.EMPTY_STRING\n );\n if (separatorLimit && +separatorLimit) {\n if (res[0] === MaskExpression.MINUS) {\n res = `-${res.slice(1, res.length).slice(0, separatorLimit.length)}`;\n } else {\n res = res.slice(0, separatorLimit.length);\n }\n }\n res = this._applyThousandGrouping(res, thousandSeparatorChar);\n\n if (typeof precision === 'undefined') {\n return res + decimals;\n } else if (precision === 0) {\n return res;\n }\n return res + decimals.substring(0, precision + 1);\n };\n\n /**\n * Formats a value for the `typeFromDecimals` mode: every digit of the raw value is\n * read as one integer that is then split `precision` digits from the right\n * (ATM/calculator style). Non-digit characters are ignored, so plain typing,\n * mid-string edits and backspace all reduce to \"digits shifted through the\n * decimal marker\".\n */\n protected _formatFromDecimals(value: string, precision: number, decimalMarker: string): string {\n const negative = this.allowNegativeNumbers && value.startsWith(MaskExpression.MINUS);\n let digits = value.replace(/\\D+/g, MaskExpression.EMPTY_STRING).replace(/^0+/, '');\n if (!digits) {\n return negative ? MaskExpression.MINUS : MaskExpression.EMPTY_STRING;\n }\n const separatorLimit: string = this.separatorLimit.replace(\n /\\s/g,\n MaskExpression.EMPTY_STRING\n );\n if (separatorLimit && +separatorLimit) {\n // Dropping the overflow from the right rejects the most recently typed\n // digits once the integer part has reached the configured limit.\n digits = digits.slice(0, separatorLimit.length + precision);\n }\n digits = digits.padStart(precision + 1, MaskExpression.NUMBER_ZERO);\n const integerPart = this._applyThousandGrouping(\n digits.slice(0, digits.length - precision),\n this.thousandSeparator\n );\n const decimalPart = digits.slice(digits.length - precision);\n return `${negative ? MaskExpression.MINUS : MaskExpression.EMPTY_STRING}${integerPart}${decimalMarker}${decimalPart}`;\n }\n\n /** Inserts `separator` between every 3-digit group of an integer-digit string. */\n private _applyThousandGrouping(digits: string, separator: string): string {\n const rgx = /(\\d+)(\\d{3})/;\n let grouped = digits;\n while (separator && rgx.test(grouped)) {\n // A function replacer: the separator is inserted verbatim, never parsed as a\n // replacement pattern ($, $&, $', ...).\n grouped = grouped.replace(\n rgx,\n (_match, head: string, tail: string) => head + separator + tail\n );\n }\n return grouped;\n }\n\n protected percentage = (str: string): boolean => {\n const sanitizedStr = str.replace(',', '.');\n const value = Number(\n this.allowNegativeNumbers && str.includes(MaskExpression.MINUS)\n ? sanitizedStr.slice(1, str.length)\n : sanitizedStr\n );\n\n return !isNaN(value) && value >= 0 && value <= 100;\n };\n\n public getPrecision = (maskExpression: string): number => {\n const x: string[] = maskExpression.split(MaskExpression.DOT);\n if (x.length > 1) {\n return Number(x[x.length - 1]);\n }\n\n return Infinity;\n };\n\n private checkAndRemoveSuffix = (inputValue: string): string => {\n for (let i = this.suffix?.length - 1; i >= 0; i--) {\n const substr = this.suffix.substring(i, this.suffix?.length);\n if (\n inputValue.endsWith(substr) &&\n i !== this.suffix?.length - 1 &&\n // A partial suffix tail (i > 0) that makes up the WHOLE value is a\n // leftover of the displayed suffix only when the previous rendered\n // value ended with the suffix AND the edit shrank the value to (or\n // below) the old value-part length, i.e. it was a deletion of the\n // suffix head. Otherwise it is fresh user input that merely collides\n // with the suffix text and must be kept (#1495).\n (i === 0 ||\n inputValue.length > substr.length ||\n (this.actualValue.endsWith(this.suffix) &&\n inputValue.length <= this.actualValue.length - this.suffix.length)) &&\n (i - 1 < 0 ||\n !inputValue.endsWith(this.suffix.substring(i - 1, this.suffix?.length)))\n ) {\n return inputValue.slice(0, inputValue.length - substr.length);\n }\n }\n return inputValue;\n };\n\n protected checkInputPrecision = (inputValue: string, precision: number): string => {\n let processedInputValue = inputValue;\n\n if (precision < Infinity) {\n const decimalMarker = this._activeDecimalMarker(inputValue);\n const precisionRegEx = new RegExp(\n this._charToRegExpExpression(decimalMarker) + `\\\\d{${precision}}.*$`\n );\n const precisionMatch: RegExpMatchArray | null =\n processedInputValue.match(precisionRegEx);\n const precisionMatchLength: number = (precisionMatch && precisionMatch[0]?.length) ?? 0;\n if (precisionMatchLength - 1 > precision) {\n const diff = precisionMatchLength - 1 - precision;\n\n processedInputValue = processedInputValue.substring(\n 0,\n processedInputValue.length - diff\n );\n }\n if (\n precision === 0 &&\n this._compareOrIncludes(\n processedInputValue[processedInputValue.length - 1],\n decimalMarker,\n this.thousandSeparator\n )\n ) {\n processedInputValue = processedInputValue.substring(\n 0,\n processedInputValue.length - 1\n );\n }\n }\n return processedInputValue;\n };\n\n protected _stripToDecimal(str: string): string {\n const isDecimalMarkerChar = (char: string): char is DecimalMarkerChar =>\n char === MaskExpression.DOT || char === MaskExpression.COMMA;\n\n return str\n .split(MaskExpression.EMPTY_STRING)\n .filter((i: string, idx: number) => {\n const isDecimalMarker =\n typeof this.decimalMarker === 'string'\n ? i === this.decimalMarker\n : isDecimalMarkerChar(i) && this.decimalMarker.includes(i);\n return (\n i.match('^-?\\\\d') ||\n i === this.thousandSeparator ||\n isDecimalMarker ||\n (i === MaskExpression.MINUS && idx === 0 && this.allowNegativeNumbers)\n );\n })\n .join(MaskExpression.EMPTY_STRING);\n }\n\n protected _charToRegExpExpression(char: string): string {\n if (!char) {\n return char;\n }\n return char === ' ' ? '\\\\s' : escapeRegExp(char);\n }\n\n protected _shiftStep(cursor: number) {\n this._shift.add(cursor + this.prefix.length || 0);\n }\n\n protected _compareOrIncludes<T>(value: T, comparedValue: T | T[], excludedValue: T): boolean {\n return Array.isArray(comparedValue)\n ? comparedValue.filter((v) => v !== excludedValue).includes(value)\n : value === comparedValue;\n }\n\n protected _validIP(valuesIP: string[]): boolean {\n return !(\n valuesIP.length === 4 &&\n !valuesIP.some((value: string, index: number) => {\n if (valuesIP.length !== index + 1) {\n return value === MaskExpression.EMPTY_STRING || Number(value) > 255;\n }\n return value === MaskExpression.EMPTY_STRING || Number(value.substring(0, 3)) > 255;\n })\n );\n }\n\n /**\n * The single rule for \"which decimal marker is active\": the configured marker, or — for an\n * array — the first configured marker present in `value` that is not the thousandSeparator,\n * else the first configured marker that is not the thousandSeparator (#1653).\n */\n protected _activeDecimalMarker(value: string): DecimalMarkerChar {\n return activeDecimalMarker(value, this.decimalMarker, this.thousandSeparator);\n }\n\n protected _splitPercentZero(value: string): string {\n if (value === MaskExpression.MINUS && this.allowNegativeNumbers) {\n return value;\n }\n const decimal = this._activeDecimalMarker(value);\n const decimalIndex = value.indexOf(decimal);\n const emptyOrMinus =\n this.allowNegativeNumbers && value.includes(MaskExpression.MINUS) ? '-' : '';\n if (decimalIndex === -1) {\n const parsedValue = parseInt(emptyOrMinus ? value.slice(1, value.length) : value, 10);\n return isNaN(parsedValue)\n ? MaskExpression.EMPTY_STRING\n : `${emptyOrMinus}${parsedValue}`;\n } else {\n const integerPart = parseInt(value.replace('-', '').substring(0, decimalIndex), 10);\n const decimalPart = value.substring(decimalIndex + 1);\n const integerString = isNaN(integerPart) ? '' : integerPart.toString();\n\n return integerString === MaskExpression.EMPTY_STRING\n ? MaskExpression.EMPTY_STRING\n : `${emptyOrMinus}${integerString}${decimal}${decimalPart}`;\n }\n }\n\n protected _findFirstNonZeroAndDecimalIndex(inputString: string, decimalMarker: '.' | ',') {\n let decimalMarkerIndex: number | null = null;\n let nonZeroIndex: number | null = null;\n\n for (let i = 0; i < inputString.length; i++) {\n const char = inputString[i];\n\n if (char === decimalMarker && decimalMarkerIndex === null) {\n decimalMarkerIndex = i;\n }\n\n if (char && char >= '1' && char <= '9' && nonZeroIndex === null) {\n nonZeroIndex = i;\n }\n\n if (decimalMarkerIndex !== null && nonZeroIndex !== null) {\n break;\n }\n }\n\n return {\n decimalMarkerIndex,\n nonZeroIndex,\n };\n }\n}\n","import { ElementRef, inject, Injectable, Renderer2, signal } from '@angular/core';\nimport { DOCUMENT } from '@angular/common';\n\nimport type { NgxMaskConfig } from './ngx-mask.config';\nimport { NGX_MASK_CONFIG } from './ngx-mask.config';\nimport { NgxMaskApplierService } from './ngx-mask-applier.service';\nimport { MaskExpression } from './ngx-mask-expression.enum';\nimport { containsStarSymbol, digitsOf, escapeRegExp, usesCommaDecimal } from './ngx-mask.utils';\n\n@Injectable()\nexport class NgxMaskService extends NgxMaskApplierService {\n public isNumberValue = false;\n public maskIsShown = '';\n public selStart: number | null = null;\n public selEnd: number | null = null;\n public maskChanged = false;\n public previousValue = '';\n public currentValue = '';\n // `writingValue` is declared on NgxMaskApplierService: applyMask needs it to\n // distinguish the writeValue flow from keystroke flows (#1611).\n public isInitialized = false;\n /**\n * Set by the directive's keepCharacterPositions handling for the current edit:\n * true — the directive fully resolved the resulting display value into actualValue,\n * so applyMask must short-circuit and render actualValue as-is;\n * false — the edit must flow through regular masking (no short-circuit);\n * null — the directive was not involved in this applyMask call (legacy behavior).\n * Consumed and reset by applyMask. This lets keepCharacterPositions work without\n * showMaskTyped (#1545, #1543).\n */\n public keepCharacterPositionsHandled: boolean | null = null;\n\n public _isFocused = signal<boolean>(false);\n\n private _emitValue = false;\n\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n public onChange = (_: unknown) => {};\n\n public readonly _elementRef = inject(ElementRef, { optional: true });\n\n private readonly document = inject(DOCUMENT);\n\n protected override _config = inject<NgxMaskConfig>(NGX_MASK_CONFIG);\n\n private readonly _renderer = inject(Renderer2, { optional: true });\n\n /**\n * Applies the mask to the input value.\n * @param inputValue The input value to be masked.\n * @param maskExpression The mask expression to apply.\n * @param position The position in the input value.\n * @param justPasted Whether the value was just pasted.\n * @param backspaced Whether the value was backspaced.\n * @param cb Callback function.\n * @returns The masked value.\n */\n public override applyMask(\n inputValue: string,\n maskExpression: string,\n position = 0,\n justPasted = false,\n backspaced = false,\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n cb: (actualShift: number, backspaceShift: boolean) => void = () => {}\n ): string {\n // Consume the directive's keepCharacterPositions verdict for this edit (see the\n // keepCharacterPositionsHandled doc). Reset immediately so it never leaks into\n // applyMask calls that do not originate from the directive's input handling.\n const kcpHandled = this.keepCharacterPositionsHandled;\n this.keepCharacterPositionsHandled = null;\n\n // If no mask expression, return the input value or the actual value\n if (!maskExpression) {\n // A RECONFIGURATION to an empty mask (mask was non-empty, now swapped to '') must\n // revert the display/model to the raw unmasked value, not the stale masked\n // `actualValue` from the mask that no longer applies (#1616: mask signal set to ''\n // on a populated control left the masked display/FormControl unchanged forever,\n // since this early return short-circuited before the `maskChanged`/emit logic\n // below ever ran). Only strip when a mask genuinely changed — a directive with no\n // mask ever configured must keep returning verbatim `actualValue`/`inputValue`.\n if (this.maskChanged) {\n const rawValue = this.removeMask(inputValue);\n this.previousValue = this.currentValue;\n this.currentValue = rawValue;\n this.actualValue = rawValue;\n this._emitValue = this.previousValue !== this.currentValue;\n if (this._emitValue && this.triggerOnMaskChange) {\n this.formControlResult(rawValue);\n }\n this._clearMaskChangedUnlessTriggered();\n return rawValue;\n }\n return inputValue !== this.actualValue ? this.actualValue : inputValue;\n }\n\n // #1492: a numeric FormControl value like 0.0000007 or 1e21 stringifies to\n // exponential notation ('7e-7'); separator masking would strip the 'e'/'-' and\n // render garbage ('77'). Expand scientific notation to plain decimal form before\n // masking. Covers writeValue-driven flows and the pipe; a keystroke value can\n // never match, since separator masking never lets a letter through.\n if (\n maskExpression.startsWith(MaskExpression.SEPARATOR) &&\n inputValue &&\n /\\d[eE][+-]?\\d/.test(inputValue)\n ) {\n const expandedNumber = Number(this._replaceDecimalMarkerToDot(inputValue));\n if (!Number.isNaN(expandedNumber)) {\n // eslint-disable-next-line no-param-reassign\n inputValue = this._toPlainDecimalString(expandedNumber);\n if (\n this.decimalMarker === MaskExpression.COMMA ||\n (Array.isArray(this.decimalMarker) &&\n this.thousandSeparator === MaskExpression.DOT)\n ) {\n // eslint-disable-next-line no-param-reassign\n inputValue = inputValue.replace(MaskExpression.DOT, MaskExpression.COMMA);\n }\n }\n }\n\n // Show mask in input if required\n this.maskIsShown = this.showMaskTyped\n ? this.showMaskInInput()\n : MaskExpression.EMPTY_STRING;\n\n // Handle specific mask expressions\n if (this.maskExpression === MaskExpression.IP && this.showMaskTyped) {\n this.maskIsShown = this.showMaskInInput(inputValue || MaskExpression.HASH);\n }\n const isCpfCnpjMask =\n this.maskExpression === MaskExpression.CPF_CNPJ ||\n this.maskExpression === MaskExpression.CPF_CNPJ_ALPHA;\n if (isCpfCnpjMask && this.showMaskTyped) {\n this.maskIsShown = this.showMaskInInput(inputValue || MaskExpression.HASH);\n }\n\n // Handle empty input value with mask typed\n if (!inputValue && this.showMaskTyped) {\n // #1590: only a USER-driven clear may propagate back to the model. When this\n // skeleton render originates from writeValue() (writingValue), emitting '' here\n // would be a view->model write inside a model->view sync — with nested CVA\n // wrappers the real initial value arrives in a LATER microtask than the initial\n // null write, and this echo overwrote it before it ever reached the view.\n if (!this.writingValue) {\n this.formControlResult(this.prefix);\n }\n // The field is now empty: record it, or retyping the previous value in one\n // input event (autofill, undo) would match the stale currentValue and never emit.\n this.previousValue = this.currentValue;\n this.currentValue = MaskExpression.EMPTY_STRING;\n return `${this.prefix}${this.maskIsShown}${this.suffix}`;\n }\n\n const getSymbol: string =\n !!inputValue && typeof this.selStart === 'number'\n ? (inputValue[this.selStart] ?? MaskExpression.EMPTY_STRING)\n : MaskExpression.EMPTY_STRING;\n let newInputValue = '';\n let newPosition = position;\n\n // Handle hidden input or input with asterisk symbol\n if (\n (this.hiddenInput ||\n (inputValue &&\n containsStarSymbol(inputValue, this.maskExpression, this.thousandSeparator))) &&\n !this.writingValue\n ) {\n // Seed from the raw input only when the user typed the FIRST character (the\n // single char is the raw symbol, actualValue is empty/stale). On backspace a\n // length-1 value is the remaining masked display (e.g. '*'), so the hidden\n // characters must come from actualValue or the deletion destroys both (#1612).\n let actualResult: string[] =\n inputValue && inputValue.length === 1 && !backspaced\n ? inputValue.split(MaskExpression.EMPTY_STRING)\n : this.actualValue.split(MaskExpression.EMPTY_STRING);\n\n // Handle backspace\n if (backspaced) {\n actualResult = actualResult\n .slice(0, position)\n .concat(actualResult.slice(position + 1));\n }\n\n // Remove mask if showMaskTyped is true\n if (this.showMaskTyped) {\n // eslint-disable-next-line no-param-reassign\n inputValue = this.removeMask(inputValue);\n actualResult = this.removeMask(actualResult.join('')).split(\n MaskExpression.EMPTY_STRING\n );\n }\n\n // Handle selection start and end\n if (typeof this.selStart === 'object' && typeof this.selEnd === 'object') {\n this.selStart = Number(this.selStart);\n this.selEnd = Number(this.selEnd);\n } else {\n if (inputValue !== MaskExpression.EMPTY_STRING && actualResult.length) {\n if (typeof this.selStart === 'number' && typeof this.selEnd === 'number') {\n if (inputValue.length > actualResult.length) {\n actualResult.splice(this.selStart, 0, getSymbol);\n } else if (inputValue.length < actualResult.length) {\n if (actualResult.length - inputValue.length === 1) {\n if (backspaced) {\n actualResult.splice(this.selStart - 1, 1);\n } else {\n actualResult.splice(inputValue.length - 1, 1);\n }\n } else {\n actualResult.splice(this.selStart, this.selEnd - this.selStart);\n }\n }\n }\n } else {\n actualResult = [];\n }\n }\n\n // Handle actual value length\n if (this.actualValue.length) {\n if (actualResult.length < inputValue.length) {\n newInputValue = this.shiftTypedSymbols(\n actualResult.join(MaskExpression.EMPTY_STRING)\n );\n } else if (actualResult.length === inputValue.length) {\n newInputValue = actualResult.join(MaskExpression.EMPTY_STRING);\n } else {\n newInputValue = inputValue;\n }\n } else {\n newInputValue = inputValue;\n }\n }\n\n // Handle just pasted input\n if (justPasted) {\n newInputValue = inputValue;\n }\n\n // Handle backspace with special characters\n if (\n backspaced &&\n this.specialCharacters.indexOf(\n this.maskExpression[newPosition] ?? MaskExpression.EMPTY_STRING\n ) !== -1 &&\n this.showMaskTyped &&\n !this.prefix\n ) {\n newInputValue = this.currentValue;\n }\n\n // Handle deleted special character\n if (this.deletedSpecialCharacter && newPosition) {\n if (\n this.specialCharacters.includes(\n this.actualValue.slice(newPosition, newPosition + 1)\n )\n ) {\n newPosition = newPosition + 1;\n } else if (\n maskExpression.slice(newPosition - 1, newPosition + 1) !== MaskExpression.MONTHS\n ) {\n newPosition = newPosition - 2;\n }\n\n this.deletedSpecialCharacter = false;\n }\n\n // Remove mask if showMaskTyped is true and placeHolderCharacter length is 1\n if (\n this.showMaskTyped &&\n this.placeHolderCharacter.length === 1 &&\n !this.leadZeroDateTime\n ) {\n newInputValue = this.removeMask(newInputValue);\n }\n\n // Handle mask changed\n if (this.maskChanged) {\n newInputValue = inputValue;\n } else {\n newInputValue =\n Boolean(newInputValue) && newInputValue.length ? newInputValue : inputValue;\n }\n\n // Handle keepCharacterPositions: when the directive resolved the display for this\n // edit (kcpHandled === true), or legacily whenever showMaskTyped is on and the\n // directive gave no explicit verdict, render actualValue as-is.\n if (\n (kcpHandled ?? this.showMaskTyped) &&\n this.keepCharacterPositions &&\n this.actualValue &&\n !justPasted &&\n !this.writingValue\n ) {\n const value = this.dropSpecialCharacters\n ? this.removeMask(this.actualValue)\n : this.actualValue;\n this.formControlResult(value);\n return this.actualValue\n ? this.actualValue\n : `${this.prefix}${this.maskIsShown}${this.suffix}`;\n }\n\n // Apply the mask using the parent class method\n const result: string = super.applyMask(\n newInputValue,\n maskExpression,\n newPosition,\n justPasted,\n backspaced,\n cb\n );\n\n // #1615: a value the mask cannot process AT ALL (masking leaves nothing of it) is\n // rendered verbatim instead of being destroyed, and must not reach formControlResult\n // — the empty remnant would clobber the model that holds the sentinel (e.g.\n // setValue('ONGOING') on a digits mask). Values that PARTIALLY match keep regular\n // masking. Two cases reach this:\n // 1. this.writingValue: the originating writeValue() call itself.\n // 2. currentValue === inputValue (and the mask didn't just change): a LATER re-render\n // replaying the exact same already-verbatim value outside of writeValue (e.g.\n // ngOnChanges re-running applyMask via the directive's _applyMask() when an\n // UNRELATED input like `disabled` changes) — without this, that pass would fall\n // through to regular masking, emit the empty result via onChange, and clobber the\n // model even though the DOM would still show the sentinel correctly.\n if (\n (this.writingValue || (!this.maskChanged && inputValue === this.currentValue)) &&\n inputValue &&\n !result &&\n this.removeMask(inputValue)\n ) {\n this.actualValue = inputValue;\n this.previousValue = this.currentValue;\n this.currentValue = inputValue;\n return inputValue;\n }\n\n this.actualValue = this.getActualValue(result);\n\n // handle some separator implications:\n // a.) adjust decimalMarker default (. -> ,) if thousandSeparator is a dot\n if (\n this.thousandSeparator === MaskExpression.DOT &&\n this.decimalMarker === MaskExpression.DOT\n ) {\n this.decimalMarker = MaskExpression.COMMA;\n }\n // b) remove decimal marker from list of special characters to mask\n if (\n this.maskExpression.startsWith(MaskExpression.SEPARATOR) &&\n this.dropSpecialCharacters === true\n ) {\n this.specialCharacters = this.specialCharacters.filter(\n (item: string) =>\n !this._compareOrIncludes(item, this.decimalMarker, this.thousandSeparator) //item !== this.decimalMarker, // !\n );\n }\n\n // Update previous and current values\n if (result || result === '') {\n this.previousValue = this.currentValue;\n this.currentValue = result;\n\n this._emitValue =\n this.previousValue !== this.currentValue ||\n (this.previousValue === this.currentValue && justPasted);\n }\n\n // Propagate the input value back to the Angular model\n // Only emit if:\n // 1. _emitValue is true (value changed), AND\n // 2. Either mask didn't change, OR triggerOnMaskChange is true\n const shouldEmit = this._emitValue && (!this.maskChanged || this.triggerOnMaskChange);\n if (shouldEmit) {\n this.formControlResult(result);\n }\n // Reset maskChanged flag even if we didn't emit\n this._clearMaskChangedUnlessTriggered();\n\n // Handle hidden input and showMaskTyped\n if (!this.showMaskTyped || (this.showMaskTyped && this.hiddenInput)) {\n if (this.hiddenInput) {\n return `${this.hideInput(result, this.maskExpression)}${this.maskIsShown.slice(result.length)}`;\n }\n return result;\n }\n\n const resLen: number = result.length;\n const prefNmask = `${this.prefix}${this.maskIsShown}${this.suffix}`;\n\n // Handle specific mask expressions\n // NOTE: IP/CPF_CNPJ/CPF_CNPJ_ALPHA are checked via exact equality BEFORE the HOURS\n // substring check below, because MaskExpression.HOURS is the single character 'H' and\n // 'CPF_CNPJ_ALPHA' contains 'H' (from \"ALPHA\"), which previously caused CPF_CNPJ_ALPHA\n // to be misrouted into the HOURS branch instead of its own branch.\n if (\n this.maskExpression === MaskExpression.IP ||\n this.maskExpression === MaskExpression.CPF_CNPJ ||\n this.maskExpression === MaskExpression.CPF_CNPJ_ALPHA\n ) {\n return `${result}${prefNmask}`;\n } else if (this.maskExpression.includes(MaskExpression.HOURS)) {\n const countSkipedSymbol = this._numberSkipedSymbols(result);\n return `${result}${prefNmask.slice(resLen + countSkipedSymbol)}`;\n }\n\n return `${result}${prefNmask.slice(resLen)}`;\n }\n\n // get the number of characters that were shifted\n private _numberSkipedSymbols(value: string): number {\n const regex = /(^|\\D)(\\d\\D)/g;\n let match = regex.exec(value);\n let countSkipedSymbol = 0;\n while (match != null) {\n countSkipedSymbol += 1;\n match = regex.exec(value);\n }\n return countSkipedSymbol;\n }\n\n public applyValueChanges(\n position: number,\n justPasted: boolean,\n backspaced: boolean,\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n cb: (actualShift: number, backspaceShift: boolean) => void = () => {}\n ): void {\n const formElement = this._elementRef?.nativeElement;\n if (!formElement) {\n return;\n }\n\n const typedValue = formElement.value;\n const maskedValue = this.applyMask(\n typedValue,\n this.maskExpression,\n position,\n justPasted,\n backspaced,\n cb\n );\n // Assigning an identical value still resets the native caret/undo state in some browsers.\n // An element that no longer holds what was typed was rewritten while the mask ran (a\n // `setValue` inside a `valueChanges` subscriber): that newer write wins (#1691).\n if (formElement.value === typedValue && formElement.value !== maskedValue) {\n formElement.value = maskedValue;\n }\n if (formElement === this._getActiveElement()) {\n return;\n }\n this.clearIfNotMatchFn();\n }\n\n public hideInput(inputValue: string, maskExpression: string): string {\n return inputValue\n .split(MaskExpression.EMPTY_STRING)\n .map((curr: string, index: number) => {\n const maskChar = maskExpression[index] ?? MaskExpression.EMPTY_STRING;\n const pattern = this.patterns?.[maskChar];\n if (pattern?.symbol) {\n return pattern.symbol;\n }\n // #1574: a '0' immediately following a concealed DAY/MONTH token\n // is that field's second digit (d0/M0) — conceal it too so the\n // whole 2-digit field is hidden, not just its first character.\n // Display-only: does not touch maskExpression/processedValue, so\n // date validation/leadZero clamping in generic-pattern.handler.ts\n // is unaffected.\n const prevMaskChar = maskExpression[index - 1];\n const prevPattern = prevMaskChar ? this.patterns?.[prevMaskChar] : null;\n if (\n maskChar === MaskExpression.NUMBER_ZERO &&\n (prevMaskChar === MaskExpression.DAY ||\n prevMaskChar === MaskExpression.MONTH) &&\n prevPattern?.symbol\n ) {\n return prevPattern.symbol;\n }\n return curr;\n })\n .join(MaskExpression.EMPTY_STRING);\n }\n\n // this function is not necessary, it checks result against maskExpression\n public getActualValue(res: string): string {\n const compare: string[] = res\n .split(MaskExpression.EMPTY_STRING)\n .filter((symbol: string, i: number) => {\n const maskChar = this.maskExpression[i] ?? MaskExpression.EMPTY_STRING;\n return (\n this._checkSymbolMask(symbol, maskChar) ||\n (this.specialCharacters.includes(maskChar) && symbol === maskChar)\n );\n });\n if (compare.join(MaskExpression.EMPTY_STRING) === res) {\n return compare.join(MaskExpression.EMPTY_STRING);\n }\n return res;\n }\n\n public shiftTypedSymbols(inputValue: string): string {\n let symbolToReplace = '';\n const newInputValue: (string | undefined)[] =\n (inputValue &&\n inputValue\n .split(MaskExpression.EMPTY_STRING)\n .map((currSymbol: string, index: number) => {\n if (\n this.specialCharacters.includes(\n inputValue[index + 1] ?? MaskExpression.EMPTY_STRING\n ) &&\n inputValue[index + 1] !== this.maskExpression[index + 1]\n ) {\n symbolToReplace = currSymbol;\n return inputValue[index + 1];\n }\n if (symbolToReplace.length) {\n const replaceSymbol: string = symbolToReplace;\n symbolToReplace = MaskExpression.EMPTY_STRING;\n return replaceSymbol;\n }\n return currSymbol;\n })) ||\n [];\n return newInputValue.join(MaskExpression.EMPTY_STRING);\n }\n\n /**\n * Convert number value to string\n * 3.1415 -> '3.1415'\n * 1e-7 -> '0.0000001'\n */\n public numberToString(value: number | string): string {\n if (\n (!value && value !== 0) ||\n (this.maskExpression.startsWith(MaskExpression.SEPARATOR) &&\n (this.leadZero || !this.dropSpecialCharacters)) ||\n (this.maskExpression.startsWith(MaskExpression.SEPARATOR) &&\n this.separatorLimit.length > 14 &&\n String(value).length > 14)\n ) {\n return String(value);\n }\n // #1573: toLocaleString('fullwide', ...) is NOT locale-independent — 'fullwide' is\n // not a real locale tag, so Intl silently falls back to the runtime DEFAULT locale\n // (e.g. de-AT on Edge with Austrian regional format emits '0,5'). Expand exponential\n // notation with pure string math instead; the decimal marker is always '.'.\n return this._toPlainDecimalString(Number(value));\n }\n\n /**\n * Locale-independent replacement for toLocaleString('fullwide', { useGrouping: false,\n * maximumFractionDigits: 20 }) (#1573): expands exponential notation ('7e-7', '1e+21')\n * to plain decimal form using '.' as decimal marker, regardless of the runtime locale.\n */\n private _toPlainDecimalString(value: number): string {\n const stringValue = String(value);\n const match = /^(-?)(\\d+)(?:\\.(\\d+))?[eE]([+-]?\\d+)$/.exec(stringValue);\n if (!match) {\n return stringValue;\n }\n const [, sign, integerPart, fractionPart = '', exponentPart] = match;\n const exponent = Number(exponentPart);\n const digits = `${integerPart}${fractionPart}`;\n const pointIndex = (integerPart as string).length + exponent;\n if (pointIndex <= 0) {\n return `${sign}0.${'0'.repeat(-pointIndex)}${digits}`;\n }\n if (pointIndex >= digits.length) {\n return `${sign}${digits}${'0'.repeat(pointIndex - digits.length)}`;\n }\n return `${sign}${digits.slice(0, pointIndex)}.${digits.slice(pointIndex)}`;\n }\n\n public showMaskInInput(inputVal?: string): string {\n if (this.showMaskTyped && !!this.shownMaskExpression) {\n if (this.maskExpression.length !== this.shownMaskExpression.length) {\n throw new Error('Mask expression must match mask placeholder length');\n } else {\n return this.shownMaskExpression;\n }\n } else if (this.showMaskTyped) {\n if (inputVal) {\n if (this.maskExpression === MaskExpression.IP) {\n return this._checkForIp(inputVal);\n }\n if (\n this.maskExpression === MaskExpression.CPF_CNPJ ||\n this.maskExpression === MaskExpression.CPF_CNPJ_ALPHA\n ) {\n return this._checkForCpfCnpj(inputVal);\n }\n }\n if (this.placeHolderCharacter.length === this.maskExpression.length) {\n return this.placeHolderCharacter;\n }\n return this.maskExpression.replace(/\\w/g, this.placeHolderCharacter);\n }\n return '';\n }\n\n public clearIfNotMatchFn(): void {\n const formElement = this._elementRef?.nativeElement;\n if (!formElement) {\n return;\n }\n if (\n this.clearIfNotMatch &&\n this.prefix.length + this.maskExpression.length + this.suffix.length !==\n formElement.value.replace(this.placeHolderCharacter, MaskExpression.EMPTY_STRING)\n .length\n ) {\n this.formElementProperty = ['value', MaskExpression.EMPTY_STRING];\n this.applyMask('', this.maskExpression);\n }\n }\n\n public set formElementProperty([name, value]: [string, string | boolean]) {\n if (!this._renderer || !this._elementRef) {\n return;\n }\n // Use queueMicrotask to defer DOM updates to next microtask.\n // This prevents ExpressionChangedAfterItHasBeenCheckedError\n // and ensures proper timing with Angular's change detection.\n queueMicrotask(() => {\n const element = this._elementRef?.nativeElement;\n if (element && Reflect.get(element, name) !== value) {\n this._renderer?.setProperty(element, name, value);\n }\n });\n }\n\n public checkDropSpecialCharAmount(mask: string): number {\n const chars: string[] = mask\n .split(MaskExpression.EMPTY_STRING)\n .filter((item: string) => this._findDropSpecialChar(item));\n return chars.length;\n }\n\n /**\n * Consumes a pending `maskChanged` once a render has handled the reconfiguration, unless\n * `triggerOnMaskChange` still needs it to emit the re-masked value (formControlResult clears\n * it then).\n */\n public _clearMaskChangedUnlessTriggered(): void {\n if (!this.triggerOnMaskChange) {\n this.maskChanged = false;\n }\n }\n\n public removeMask(inputValue: string): string {\n return this._removeMask(\n this._removeSuffix(this._removePrefix(inputValue)),\n this.specialCharacters.concat('_').concat(this.placeHolderCharacter)\n );\n }\n\n private _checkForIp(inputVal: string): string {\n if (inputVal === MaskExpression.HASH) {\n return `${this.placeHolderCharacter}.${this.placeHolderCharacter}.${this.placeHolderCharacter}.${this.placeHolderCharacter}`;\n }\n const arr = digitsOf(inputVal);\n if (arr.length <= 3) {\n return `${this.placeHolderCharacter}.${this.placeHolderCharacter}.${this.placeHolderCharacter}`;\n }\n if (arr.length > 3 && arr.length <= 6) {\n return `${this.placeHolderCharacter}.${this.placeHolderCharacter}`;\n }\n if (arr.length > 6 && arr.length <= 9) {\n return this.placeHolderCharacter;\n }\n if (arr.length > 9 && arr.length <= 12) {\n return '';\n }\n return '';\n }\n\n private _checkForCpfCnpj(inputVal: string): string {\n const cpf =\n `${this.placeHolderCharacter}${this.placeHolderCharacter}${this.placeHolderCharacter}` +\n `.${this.placeHolderCharacter}${this.placeHolderCharacter}${this.placeHolderCharacter}` +\n `.${this.placeHolderCharacter}${this.placeHolderCharacter}${this.placeHolderCharacter}` +\n `-${this.placeHolderCharacter}${this.placeHolderCharacter}`;\n const cnpj =\n `${this.placeHolderCharacter}${this.placeHolderCharacter}` +\n `.${this.placeHolderCharacter}${this.placeHolderCharacter}${this.placeHolderCharacter}` +\n `.${this.placeHolderCharacter}${this.placeHolderCharacter}${this.placeHolderCharacter}` +\n `/${this.placeHolderCharacter}${this.placeHolderCharacter}${this.placeHolderCharacter}${this.placeHolderCharacter}` +\n `-${this.placeHolderCharacter}${this.placeHolderCharacter}`;\n\n if (inputVal === MaskExpression.HASH) {\n return cpf;\n }\n\n const isCpfCnpjAlpha = this.maskExpression === MaskExpression.CPF_CNPJ_ALPHA;\n const hasAnyLetter = /[a-zA-Z]/.test(inputVal);\n const arr = this._countCpfCnpjTypedChars(inputVal, isCpfCnpjAlpha);\n if (isCpfCnpjAlpha && hasAnyLetter) {\n // CNPJ_ALPHA shape is \"AA.AAA.AAA/AAAA-00\": separators fall after the 2nd, 5th,\n // 8th and 12th typed character, so the placeholder slice offset must account for\n // however many separators `result` has already passed through, mirroring the\n // numeric CPF/CNPJ bucketed offsets below.\n if (arr.length <= 2) {\n return cnpj.slice(arr.length, cnpj.length);\n }\n if (arr.length > 2 && arr.length <= 5) {\n return cnpj.slice(arr.length + 1, cnpj.length);\n }\n if (arr.length > 5 && arr.length <= 8) {\n return cnpj.slice(arr.length + 2, cnpj.length);\n }\n if (arr.length > 8 && arr.length <= 12) {\n return cnpj.slice(arr.length + 3, cnpj.length);\n }\n return cnpj.slice(arr.length + 4, cnpj.length);\n } else {\n if (arr.length <= 3) {\n return cpf.slice(arr.length, cpf.length);\n }\n if (arr.length > 3 && arr.length <= 6) {\n return cpf.slice(arr.length + 1, cpf.length);\n }\n if (arr.length > 6 && arr.length <= 9) {\n return cpf.slice(arr.length + 2, cpf.length);\n }\n if (arr.length > 9 && arr.length < 11) {\n return cpf.slice(arr.length + 3, cpf.length);\n }\n }\n if (arr.length === 11) {\n return '';\n }\n if (arr.length === 12) {\n if (inputVal.length === 17) {\n return cnpj.slice(16, cnpj.length);\n }\n return cnpj.slice(15, cnpj.length);\n }\n if (arr.length > 12 && arr.length <= 14) {\n return cnpj.slice(arr.length + 4, cnpj.length);\n }\n return '';\n }\n\n /** Collects the characters counted as \"typed\" for CPF/CNPJ progress tracking: digits only\n * for the numeric mask, alphanumerics for CPF_CNPJ_ALPHA. */\n private _countCpfCnpjTypedChars(inputVal: string, isCpfCnpjAlpha: boolean): string[] {\n return isCpfCnpjAlpha ? (inputVal.match(/[a-zA-Z0-9]/g) ?? []) : digitsOf(inputVal);\n }\n\n /**\n * Recursively determine the current active element by navigating the Shadow DOM until the Active Element is found.\n */\n public _getActiveElement(document: DocumentOrShadowRoot = this.document): Element | null {\n const shadowRootEl = document?.activeElement?.shadowRoot;\n if (!shadowRootEl?.activeElement) {\n return document.activeElement;\n } else {\n return this._getActiveElement(shadowRootEl);\n }\n }\n\n /**\n * Propogates the input value back to the Angular model by triggering the onChange function. It won't do this if writingValue\n * is true. If that is true it means we are currently in the writeValue function, which is supposed to only update the actual\n * DOM element based on the Angular model value. It should be a one way process, i.e. writeValue should not be modifying the Angular\n * model value too. Therefore, we don't trigger onChange in this scenario.\n * @param inputValue the current form input value\n */\n public formControlResult(inputValue: string): void {\n const outputTransformFn = this.outputTransformFn\n ? this.outputTransformFn\n : (v: unknown) => v;\n\n this.writingValue = false;\n this.maskChanged = false;\n\n if (!this.isInitialized && this._emitValue) {\n return;\n }\n\n // #1519: a non-special placeHolderCharacter (e.g. 'X') is never something the user\n // typed — it's the showMaskTyped fill character for unfilled slots — so it must never\n // reach the model, regardless of dropSpecialCharacters. The default '_' placeholder is\n // already covered by specialCharacters/removeMask; a custom single-char placeholder\n // that isn't a special character is not, since none of the branches below include it\n // in their removal set.\n if (\n this.showMaskTyped &&\n this.placeHolderCharacter.length === 1 &&\n this.specialCharacters.indexOf(this.placeHolderCharacter) === -1\n ) {\n // eslint-disable-next-line no-param-reassign\n inputValue = inputValue\n .split(this.placeHolderCharacter)\n .join(MaskExpression.EMPTY_STRING);\n }\n\n // #1668: an email address is meaningless without its '@' and '.', so the built-in\n // email mask always reports the full address, whatever dropSpecialCharacters says.\n const keepSpecialCharacters = this.maskExpression === MaskExpression.EMAIL_MASK;\n\n if (Array.isArray(this.dropSpecialCharacters) && !keepSpecialCharacters) {\n this.onChange(\n outputTransformFn(\n this._toNumber(\n this._checkSymbols(\n this._removeMask(\n this._removeSuffix(this._removePrefix(inputValue)),\n this.dropSpecialCharacters\n )\n )\n )\n )\n );\n } else if (\n !keepSpecialCharacters &&\n (this.dropSpecialCharacters ||\n (!this.dropSpecialCharacters && this.prefix === inputValue))\n ) {\n this.onChange(\n outputTransformFn(\n this._toNumber(\n this._checkSymbols(this._removeSuffix(this._removePrefix(inputValue)))\n )\n )\n );\n } else {\n this.onChange(outputTransformFn(this._toNumber(inputValue)));\n }\n }\n\n private _toNumber(value: string | number | undefined | null) {\n if (!this.isNumberValue || value === MaskExpression.EMPTY_STRING) {\n return value;\n }\n if (\n this.maskExpression.startsWith(MaskExpression.SEPARATOR) &&\n (this.leadZero || !this.dropSpecialCharacters)\n ) {\n return value;\n }\n\n if (String(value).length > 14 && this.maskExpression.startsWith(MaskExpression.SEPARATOR)) {\n return String(value);\n }\n\n const num = Number(value);\n if (this.maskExpression.startsWith(MaskExpression.SEPARATOR) && Number.isNaN(num)) {\n const val = String(value).replace(',', '.');\n return Number(val);\n }\n\n return Number.isNaN(num) ? value : num;\n }\n\n private _removeMask(value: string, specialCharactersForRemove: string[]): string {\n if (\n this.maskExpression.startsWith(MaskExpression.PERCENT) &&\n (value.includes(MaskExpression.DOT) ||\n (Array.isArray(this.decimalMarker) &&\n value.includes(MaskExpression.COMMA) &&\n this._activeDecimalMarker(value) === MaskExpression.COMMA))\n ) {\n return value;\n }\n\n return value\n ? value.replace(\n this._regExpForRemove(specialCharactersForRemove),\n MaskExpression.EMPTY_STRING\n )\n : value;\n }\n\n private _removePrefix(value: string): string {\n if (!this.prefix) {\n return value;\n }\n return value ? value.replace(this.prefix, MaskExpression.EMPTY_STRING) : value;\n }\n\n private _removeSuffix(value: string): string {\n if (!this.suffix) {\n return value;\n }\n return value ? value.replace(this.suffix, MaskExpression.EMPTY_STRING) : value;\n }\n\n private _retrieveSeparatorValue(result: string): string {\n let specialCharacters = Array.isArray(this.dropSpecialCharacters)\n ? this.specialCharacters.filter((v) => {\n return (this.dropSpecialCharacters as string[]).includes(v);\n })\n : this.specialCharacters;\n if (\n !this.deletedSpecialCharacter &&\n this._checkPatternForSpace() &&\n result.includes(MaskExpression.WHITE_SPACE) &&\n this.maskExpression.includes(MaskExpression.SYMBOL_STAR)\n ) {\n specialCharacters = specialCharacters.filter(\n (char) => char !== MaskExpression.WHITE_SPACE\n );\n }\n\n // A separator mask groups with the configured thousandSeparator, which need not be one of\n // the specialCharacters (`$`, `*`, `^`, `|`...). It is never part of the number, so strip it\n // like the default ' ' and ',' unless the caller listed what to drop explicitly.\n if (\n !Array.isArray(this.dropSpecialCharacters) &&\n this.maskExpression.startsWith(MaskExpression.SEPARATOR) &&\n this.thousandSeparator &&\n !specialCharacters.includes(this.thousandSeparator)\n ) {\n specialCharacters = [...specialCharacters, this.thousandSeparator];\n }\n\n return this._removeMask(result, specialCharacters as string[]);\n }\n\n private _regExpForRemove(specialCharactersForRemove: string[]): RegExp {\n return new RegExp(\n specialCharactersForRemove.map((item: string) => escapeRegExp(item)).join('|'),\n 'gi'\n );\n }\n\n private _replaceDecimalMarkerToDot(value: string): string {\n const markers = Array.isArray(this.decimalMarker)\n ? this.decimalMarker\n : [this.decimalMarker];\n\n return value.replace(this._regExpForRemove(markers), MaskExpression.DOT);\n }\n\n public _checkSymbols(result: string): string | number | undefined | null {\n let processedResult = result;\n\n if (processedResult === MaskExpression.EMPTY_STRING) {\n return processedResult;\n }\n\n if (\n this.maskExpression.startsWith(MaskExpression.PERCENT) &&\n this._activeDecimalMarker(processedResult) === MaskExpression.COMMA\n ) {\n processedResult = processedResult.replace(MaskExpression.COMMA, MaskExpression.DOT);\n }\n const separatorPrecision: number | null = this._retrieveSeparatorPrecision(\n this.maskExpression\n );\n\n const separatorValue: string =\n this.specialCharacters.length === 0\n ? this._retrieveSeparatorValue(processedResult)\n : this._replaceDecimalMarkerToDot(this._retrieveSeparatorValue(processedResult));\n\n if (!this.isNumberValue) {\n return separatorValue;\n }\n if (separatorPrecision) {\n if (processedResult === this.decimalMarker) {\n return null;\n }\n if (separatorValue.length > 14) {\n return String(separatorValue);\n }\n return this._checkPrecision(this.maskExpression, separatorValue);\n } else {\n return separatorValue;\n }\n }\n\n private _checkPatternForSpace(): boolean {\n for (const key in this.patterns) {\n // eslint-disable-next-line no-prototype-builtins\n if (this.patterns[key] && this.patterns[key]?.hasOwnProperty('pattern')) {\n const patternString = this.patterns[key]?.pattern.toString();\n const pattern = this.patterns[key]?.pattern;\n if (\n (patternString?.includes(MaskExpression.WHITE_SPACE) as boolean) &&\n pattern &&\n this._testPattern(pattern, this.maskExpression)\n ) {\n return true;\n }\n }\n }\n return false;\n }\n private _retrieveSeparatorPrecision(maskExpression: string): number | null {\n const matcher: RegExpMatchArray | null = maskExpression.match(\n new RegExp(`^separator\\\\.([^d]*)`)\n );\n return matcher ? Number(matcher[1]) : null;\n }\n\n public _checkPrecision(separatorExpression: string, separatorValue: string): number | string {\n const separatorPrecision = this.getPrecision(separatorExpression);\n let value = separatorValue;\n\n if (\n (separatorExpression.indexOf('2') > 0 && !this._isFocused()) ||\n (this.leadZero &&\n !this._isFocused() &&\n Number(separatorPrecision) > 0 &&\n Number.isFinite(separatorPrecision))\n ) {\n if (\n this.leadZero &&\n usesCommaDecimal(value, this.decimalMarker, this.thousandSeparator)\n ) {\n value = value.replace(MaskExpression.COMMA, MaskExpression.DOT);\n }\n if (Number.isNaN(Number(value))) {\n // Not a number the padding can read: show it unpadded rather than as 'NaN'.\n return separatorValue;\n }\n const precision = this.leadZero ? Number(separatorPrecision) : 2;\n // #1567: Number(value).toFixed() corrupts values with more significant digits\n // than an IEEE-754 double can hold (e.g. '999999999999999.99' becomes\n // '1000000000000000.00'). Round such values textually instead; safe-range\n // values keep the original toFixed() semantics.\n if (this._exceedsDoublePrecision(value)) {\n return this._stringToFixed(value, precision);\n }\n return Number(value).toFixed(precision);\n }\n return this.numberToString(value);\n }\n\n /**\n * True when the plain decimal string carries more significant digits than an IEEE-754\n * double can represent exactly (15 is the guaranteed round-trip digit count), meaning a\n * Number() round-trip would corrupt it (#1567).\n */\n private _exceedsDoublePrecision(value: string): boolean {\n if (!/^-?\\d+(\\.\\d+)?$/.test(value)) {\n return false;\n }\n const significantDigits = value.replace(/\\D/g, '').replace(/^0+/, '');\n return significantDigits.length > 15;\n }\n\n /**\n * Exact string-based equivalent of Number.prototype.toFixed (round half away from zero)\n * for plain decimal strings beyond double precision (#1567).\n */\n private _stringToFixed(value: string, precision: number): string {\n const isNegative = value.startsWith(MaskExpression.MINUS);\n const absValue = isNegative ? value.slice(1) : value;\n const [integerPart = '0', fractionPart = ''] = absValue.split(MaskExpression.DOT);\n const paddedFraction = fractionPart.padEnd(precision + 1, '0');\n const keptFraction = paddedFraction.slice(0, precision);\n const shouldRoundUp = (paddedFraction.charCodeAt(precision) || 0) >= 53; // '5'\n let scaled = BigInt(integerPart + keptFraction);\n if (shouldRoundUp) {\n scaled += 1n;\n }\n const digits = scaled.toString().padStart(precision + 1, '0');\n const sign = isNegative && scaled > 0n ? MaskExpression.MINUS : '';\n return precision > 0\n ? `${sign}${digits.slice(0, -precision)}.${digits.slice(-precision)}`\n : `${sign}${digits}`;\n }\n\n public _repeatPatternSymbols(maskExp: string): string {\n let start = 0;\n return (\n (maskExp.match(/{[0-9]+}/) &&\n maskExp\n .split(MaskExpression.EMPTY_STRING)\n .reduce((accum: string, currVal: string, index: number): string => {\n start = currVal === MaskExpression.CURLY_BRACKETS_LEFT ? index : start;\n if (currVal !== MaskExpression.CURLY_BRACKETS_RIGHT) {\n return this._findSpecialChar(currVal) ? accum + currVal : accum;\n }\n const repeatNumber = Number(maskExp.slice(start + 1, index));\n const replaceWith: string = new Array(repeatNumber + 1).join(\n maskExp[start - 1]\n );\n if (\n maskExp.slice(0, start).length > 1 &&\n maskExp.includes(MaskExpression.LETTER_S)\n ) {\n const symbols = maskExp.slice(0, start - 1);\n return symbols.includes(MaskExpression.CURLY_BRACKETS_LEFT)\n ? accum + replaceWith\n : symbols + accum + replaceWith;\n } else {\n return accum + replaceWith;\n }\n }, '')) ||\n maskExp\n );\n }\n\n /**\n * Decimal marker of the value being normalized in writeValue/pipe flows.\n *\n * #1573: this used to return the RUNTIME default locale's decimal marker\n * ((1.1).toLocaleString().substring(1, 2)), which made mask behavior depend on the\n * OS/browser regional format: under a comma-decimal locale (e.g. Edge + Austrian\n * regional settings) a preformatted value like '10,000' (thousandSeparator ',')\n * had its ',' replaced by the configured '.' decimalMarker, corrupting the value\n * 1000x. JS number stringification (String(n)) always uses '.', and string values\n * are expected to use the configured markers — the runtime locale is never the\n * right source, so this is always '.'.\n */\n public currentLocaleDecimalMarker(): string {\n return MaskExpression.DOT;\n }\n}\n","import type { EnvironmentProviders, Provider } from '@angular/core';\nimport { inject, makeEnvironmentProviders } from '@angular/core';\n\nimport type { NgxMaskOptions } from './ngx-mask.config';\nimport { NGX_MASK_CONFIG, INITIAL_CONFIG, initialConfig, NEW_CONFIG } from './ngx-mask.config';\nimport { NgxMaskService } from './ngx-mask.service';\n\n/**\n * @internal\n */\nfunction _configFactory(): NgxMaskOptions {\n const initConfig = inject<NgxMaskOptions>(INITIAL_CONFIG);\n const configValue = inject<NgxMaskOptions | (() => NgxMaskOptions)>(NEW_CONFIG);\n\n return configValue instanceof Function\n ? { ...initConfig, ...configValue() }\n : { ...initConfig, ...configValue };\n}\n\nexport function provideNgxMask(configValue?: NgxMaskOptions | (() => NgxMaskOptions)): Provider[] {\n return [\n {\n provide: NEW_CONFIG,\n useValue: configValue,\n },\n {\n provide: INITIAL_CONFIG,\n useValue: initialConfig,\n },\n {\n provide: NGX_MASK_CONFIG,\n useFactory: _configFactory,\n },\n NgxMaskService,\n ];\n}\n\nexport function provideEnvironmentNgxMask(\n configValue?: NgxMaskOptions | (() => NgxMaskOptions)\n): EnvironmentProviders {\n return makeEnvironmentProviders(provideNgxMask(configValue));\n}\n","import { MaskExpression } from '../ngx-mask-expression.enum';\nimport type { NgxMaskService } from '../ngx-mask.service';\nimport { nextFillableIndex } from '../ngx-mask.utils';\n\n/** The mask service state the resolution reads; plain property reads, nothing is written back. */\nexport type KeepCharacterPositionsState = Readonly<\n Pick<\n NgxMaskService,\n | 'prefix'\n | 'suffix'\n | 'showMaskTyped'\n | 'maskExpression'\n | 'maskIsShown'\n | 'placeHolderCharacter'\n | 'specialCharacters'\n | 'selStart'\n | 'selEnd'\n | 'actualValue'\n | '_checkSymbolMask'\n >\n>;\n\n/** The edit being resolved. */\nexport type KeepCharacterPositionsEdit = {\n /** The value of the element after the edit. */\n elValue: string;\n /** The caret of the element after the edit, already shifted by the prefix for a first character. */\n position: number;\n /** The key code of the edit. */\n code: string;\n /** The display value before the edit. */\n before: string;\n};\n\nexport type KeepCharacterPositionsResult = {\n /** The resolved display value, or null when the current actualValue stays as it is. */\n actualValue: string | null;\n position: number;\n /**\n * Whether the edit was fully resolved into `actualValue`: applyMask then renders it as-is.\n * When false it flows through regular masking (e.g. appending at the end, clearing it all).\n */\n handled: boolean;\n};\n\n/**\n * Resolves one edit of a `keepCharacterPositions` mask: the layout of the mask is kept, so a\n * deleted character leaves a placeholder behind and a typed one overwrites the next fillable slot.\n */\nexport function resolveKeepCharacterPositions(\n svc: KeepCharacterPositionsState,\n edit: KeepCharacterPositionsEdit\n): KeepCharacterPositionsResult {\n const {\n prefix,\n suffix,\n showMaskTyped,\n maskExpression,\n placeHolderCharacter,\n specialCharacters,\n selStart: selStartRaw,\n selEnd: selEndRaw,\n } = svc;\n const { elValue } = edit;\n let position = edit.position;\n let actualValue: string | null = null;\n const inputSymbol = elValue.slice(position - 1, position);\n const prefixLength = prefix.length;\n // Placeholder skeleton of the mask (special chars kept, fillable slots\n // replaced by the placeholder character). With showMaskTyped the service\n // renders it as maskIsShown; without showMaskTyped it is derived locally so\n // keepCharacterPositions works on its own (#1545, #1543).\n const maskSkeleton: string = svc.maskIsShown.length\n ? svc.maskIsShown\n : maskExpression.replace(/\\w/g, placeHolderCharacter);\n\n const hasSelection: boolean = selStartRaw !== selEndRaw;\n const selStartAbs = Number(selStartRaw);\n const selEndAbs = Number(selEndRaw);\n const selStart = selStartAbs - prefixLength;\n const selEnd = selEndAbs - prefixLength;\n // The display before the edit, when the element still holds the part before the selection\n // and has the length it had before the edit; null when `before` cannot be trusted, or when\n // the field is still empty (its display is a bare skeleton that regular masking fills).\n const restoreBefore = (preEditLength: number): string | null =>\n svc.actualValue &&\n edit.before.length === preEditLength &&\n edit.before.startsWith(elValue.slice(0, selStartAbs))\n ? edit.before\n : null;\n\n // Without showMaskTyped the suffix follows the last digit, so the end of the mask part is read\n // from the display before the edit, not from the skeleton, and a selection blanks no more of\n // the skeleton than the mask part of that display.\n const maskEndOf = (preEditLength: number): number => preEditLength - suffix.length;\n const blankEndOf = (preEditLength: number): number =>\n Math.max(Math.min(selEndAbs, maskEndOf(preEditLength)) - prefixLength, 0);\n\n const backspaceOrDelete =\n edit.code === MaskExpression.BACKSPACE || edit.code === MaskExpression.DELETE;\n\n let handled = true;\n // Where the mask part ends once a selection delete trimmed its trailing gaps: with a suffix\n // the caret must not land in it.\n let trimmedBodyEnd: number | null = null;\n\n if (backspaceOrDelete) {\n if (hasSelection) {\n const preEditLength = elValue.length + (selEndAbs - selStartAbs);\n const maskEndAbs = maskEndOf(preEditLength);\n const blankEnd = blankEndOf(preEditLength);\n // What follows the selection: the display before the edit, which still carries the\n // skeleton tail of a value written through the control (its actualValue is bare).\n const displayBefore = restoreBefore(preEditLength) ?? svc.actualValue;\n if (!showMaskTyped && selStartAbs <= prefixLength && selEndAbs >= preEditLength) {\n // The whole value was selected and deleted: clear through the\n // regular path instead of showing a placeholder skeleton.\n handled = false;\n } else if (selStartRaw === prefixLength) {\n // A selection that reaches into the suffix took part of it out of the element.\n const rest = selEndAbs > maskEndAbs ? suffix : elValue.split(prefix).join('');\n actualValue = `${prefix}${maskSkeleton.slice(0, blankEnd)}${rest}`;\n } else if (selStartRaw === maskSkeleton.length + prefixLength) {\n actualValue = `${elValue}${maskSkeleton.slice(selStart, selEnd)}`;\n } else {\n actualValue = `${prefix}${elValue\n .split(prefix)\n .join('')\n .slice(\n 0,\n selStart\n )}${maskSkeleton.slice(selStart, blankEnd)}${displayBefore.slice(\n selEndAbs,\n maskEndAbs\n )}${suffix}`;\n }\n if (!showMaskTyped && actualValue !== null && selEndAbs >= maskEndAbs) {\n // The selection reached the end of the mask part: nothing follows its placeholders\n // and separators, drop them (leading and middle gaps stay).\n const bodyEnd = actualValue.endsWith(suffix)\n ? actualValue.length - suffix.length\n : actualValue.length;\n let end = bodyEnd;\n while (\n end > prefixLength &&\n (actualValue.charAt(end - 1) === placeHolderCharacter ||\n specialCharacters.includes(actualValue.charAt(end - 1)))\n ) {\n end--;\n }\n actualValue = `${actualValue.slice(0, end)}${actualValue.slice(bodyEnd)}`;\n trimmedBodyEnd = end;\n }\n } else if (\n !specialCharacters.includes(\n maskExpression.slice(position - prefixLength, position + 1 - prefixLength)\n )\n ) {\n if (!showMaskTyped && position >= elValue.length) {\n // Deleting the last character: no gap needs to be kept.\n handled = false;\n } else if (selStart === 1 && prefix) {\n actualValue = `${prefix}${placeHolderCharacter}${elValue\n .split(prefix)\n .join('')\n .split(suffix)\n .join('')}${suffix}`;\n\n position = position - 1;\n } else {\n const part1 = elValue.substring(0, position);\n const part2 = elValue.substring(position);\n actualValue = `${part1}${placeHolderCharacter}${part2}`;\n }\n }\n // A collapsed Delete steps past the blank it leaves; a deleted selection leaves the caret\n // on its first blank, like Backspace, so the next digit fills it.\n position = edit.code === MaskExpression.DELETE && !hasSelection ? position + 1 : position;\n if (trimmedBodyEnd !== null && suffix) {\n position = Math.min(position, trimmedBodyEnd);\n }\n } else if (hasSelection) {\n // A selected range was replaced by the typed symbol. Keep the layout:\n // blank the selection to the mask skeleton and put the typed symbol\n // into the first fillable slot of the selection (#1527, #1489).\n const preEditLength = elValue.length - 1 + (selEndAbs - selStartAbs);\n // The symbol replaced the selection, so it sits at the selection start; `position` is\n // shifted by the prefix for a first character and would point at the next one.\n const typedSymbol = elValue.charAt(selStartAbs);\n if (!showMaskTyped && selStartAbs <= prefixLength && selEndAbs >= preEditLength) {\n // The whole value was replaced: mask it through the regular path.\n handled = false;\n } else {\n const maskIdx = nextFillableIndex(\n maskExpression,\n specialCharacters,\n Math.max(selStart, 0)\n );\n // A selection that reaches into the prefix or the suffix took part of them out of the\n // element: restore those from the service instead of reading the damaged fragments.\n const head = selStartAbs < prefixLength ? prefix : elValue.slice(0, selStartAbs);\n const maskEndAbs = maskEndOf(preEditLength);\n // The rest of a prefix that the selection ended inside follows the symbol: skip it.\n const prefixLeft = Math.max(prefixLength - selEndAbs, 0);\n const tail =\n selEndAbs > maskEndAbs ? suffix : elValue.slice(selStartAbs + 1 + prefixLeft);\n const blankEnd = blankEndOf(preEditLength);\n const blanked = `${head}${maskSkeleton.slice(Math.max(selStart, 0), blankEnd)}${tail}`;\n const targetAbs = maskIdx + prefixLength;\n if (\n targetAbs < blanked.length - suffix.length &&\n svc._checkSymbolMask(\n typedSymbol,\n maskExpression[maskIdx] ?? MaskExpression.EMPTY_STRING\n )\n ) {\n actualValue = `${blanked.slice(0, targetAbs)}${typedSymbol}${blanked.slice(targetAbs + 1)}`;\n position = targetAbs + 1;\n } else {\n // Rejected symbol: keep the display from before the key, else the blanked one.\n actualValue = restoreBefore(preEditLength) ?? blanked;\n position = Math.max(selStartAbs, prefixLength);\n }\n }\n } else {\n // Single-caret insert (overwrite mode): the typed symbol lands in the\n // first fillable mask slot at or after the caret, skipping any number\n // of special characters (#1544, #1489).\n const oldDisplay = `${elValue.slice(0, position - 1)}${elValue.slice(position)}`;\n const oldDisplayNoSuffix = suffix ? oldDisplay.split(suffix).join('') : oldDisplay;\n if (position - 1 - prefixLength < 0) {\n // Typed inside the prefix: reject the symbol.\n actualValue = restoreBefore(elValue.length - 1);\n position = position - 1;\n } else {\n const maskIdx = nextFillableIndex(\n maskExpression,\n specialCharacters,\n position - 1 - prefixLength\n );\n const targetAbs = maskIdx + prefixLength;\n if (targetAbs >= oldDisplayNoSuffix.length) {\n if (oldDisplayNoSuffix.length <= prefixLength || !showMaskTyped) {\n // First symbol, or appending at the end without\n // showMaskTyped: regular masking handles it (including\n // leadZeroDateTime insertions).\n handled = false;\n } else {\n // All slots of the rendered mask are already consumed.\n actualValue = restoreBefore(elValue.length - 1);\n position = position - 1;\n }\n } else if (\n svc._checkSymbolMask(\n inputSymbol,\n maskExpression[maskIdx] ?? MaskExpression.EMPTY_STRING\n )\n ) {\n actualValue = `${oldDisplayNoSuffix.slice(0, targetAbs)}${inputSymbol}${oldDisplayNoSuffix.slice(targetAbs + 1)}${suffix}`;\n position = targetAbs + 1;\n } else {\n // Rejected symbol: keep the current display.\n actualValue = restoreBefore(elValue.length - 1);\n position = position - 1;\n }\n }\n }\n return { actualValue, position, handled };\n}\n","import type { OnChanges, SimpleChanges } from '@angular/core';\nimport {\n afterNextRender,\n Injector,\n NgZone,\n signal,\n input,\n output,\n model,\n effect,\n Directive,\n inject,\n untracked,\n booleanAttribute,\n ChangeDetectorRef,\n ElementRef,\n Renderer2,\n} from '@angular/core';\nimport type {\n ControlValueAccessor,\n FormControl,\n ValidationErrors,\n Validator,\n} from '@angular/forms';\nimport { NgControl } from '@angular/forms';\nimport { NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport type { FormValueControl } from '@angular/forms/signals';\n\nimport type { NgxMaskConfig } from './ngx-mask.config';\nimport { NGX_MASK_CONFIG, resolveMaskAlias, timeMasks, withoutValidation } from './ngx-mask.config';\nimport {\n isDateTimeMask,\n leadZeroDateTimeCaret,\n overwriteDateSlot,\n overwriteFullDateValue,\n setUserEdit,\n} from './caret/date-overflow';\nimport { resolveKeepCharacterPositions } from './caret/keep-character-positions';\nimport { NgxMaskService } from './ngx-mask.service';\nimport { MaskExpression } from './ngx-mask-expression.enum';\nimport {\n containsStarSymbol,\n displayToPlainDecimal,\n escapeRegExp,\n retargetSeparatorValue,\n usesCommaDecimal,\n} from './ngx-mask.utils';\n\nconst notFilled = (errors: ValidationErrors | null) => ({ errors, filled: false });\n\n/** Index where the suffix starts in the display, or Infinity when the display carries none (hiddenInput). */\nconst suffixStart = (display: string, suffix: string): number =>\n suffix && display.endsWith(suffix) ? display.length - suffix.length : Infinity;\n\n// Inputs copied verbatim onto NgxMaskService by ngOnChanges (see `_mirrorInput`).\nconst MIRRORED_INPUTS = [\n 'instantPrefix',\n 'prefix',\n 'suffix',\n 'decimalMarker',\n 'dropSpecialCharacters',\n 'shownMaskExpression',\n 'clearIfNotMatch',\n 'validation',\n 'separatorLimit',\n 'typeFromDecimals',\n 'leadZeroDateTime',\n 'leadZero',\n 'triggerOnMaskChange',\n 'inputTransformFn',\n 'outputTransformFn',\n 'keepCharacterPositions',\n] as const satisfies readonly (keyof NgxMaskService & keyof NgxMaskDirective)[];\n\ntype MirroredInput = (typeof MIRRORED_INPUTS)[number];\n\n@Directive({\n selector: 'input[mask], textarea[mask]',\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: NgxMaskDirective,\n multi: true,\n },\n {\n provide: NG_VALIDATORS,\n useExisting: NgxMaskDirective,\n multi: true,\n },\n NgxMaskService,\n ],\n exportAs: 'mask,ngxMask',\n host: {\n '(paste)': 'onPaste()',\n '(focus)': 'onFocus()',\n '(ngModelChange)': 'onModelChange($event)',\n '(input)': 'onInput($event)',\n '(compositionstart)': 'onCompositionStart()',\n '(compositionend)': 'onCompositionEnd($event)',\n '(blur)': 'onBlur($event)',\n '(click)': 'onClick($event)',\n '(keydown)': 'onKeyDown($event)',\n },\n})\nexport class NgxMaskDirective\n implements\n ControlValueAccessor,\n OnChanges,\n Validator,\n FormValueControl<string | number | null | undefined>\n{\n // ===== Mask Configuration Inputs =====\n public mask = input<string | undefined | null>('');\n public specialCharacters = input<NgxMaskConfig['specialCharacters']>([]);\n public patterns = input<NgxMaskConfig['patterns']>({});\n public prefix = input<NgxMaskConfig['prefix']>('');\n public suffix = input<NgxMaskConfig['suffix']>('');\n public thousandSeparator = input<NgxMaskConfig['thousandSeparator']>(' ');\n public decimalMarker = input<NgxMaskConfig['decimalMarker']>('.');\n public dropSpecialCharacters = input<NgxMaskConfig['dropSpecialCharacters'] | null>(null);\n public hiddenInput = input<NgxMaskConfig['hiddenInput'] | null>(null);\n public showMaskTyped = input<NgxMaskConfig['showMaskTyped'] | null>(null);\n public placeHolderCharacter = input<NgxMaskConfig['placeHolderCharacter'] | null>(null);\n public shownMaskExpression = input<NgxMaskConfig['shownMaskExpression'] | null>(null);\n public clearIfNotMatch = input<NgxMaskConfig['clearIfNotMatch'] | null>(null);\n public validation = input<NgxMaskConfig['validation'] | null>(null);\n public separatorLimit = input<NgxMaskConfig['separatorLimit'] | null>('');\n public typeFromDecimals = input<NgxMaskConfig['typeFromDecimals'] | null>(null);\n public allowNegativeNumbers = input<NgxMaskConfig['allowNegativeNumbers'] | null>(null);\n public leadZeroDateTime = input<NgxMaskConfig['leadZeroDateTime'] | null>(null);\n public leadZero = input<NgxMaskConfig['leadZero'] | null>(null);\n public triggerOnMaskChange = input<NgxMaskConfig['triggerOnMaskChange'] | null>(null);\n public apm = input<NgxMaskConfig['apm'] | null>(null);\n public inputTransformFn = input<NgxMaskConfig['inputTransformFn'] | null>(null);\n public outputTransformFn = input<NgxMaskConfig['outputTransformFn'] | null>(null);\n public keepCharacterPositions = input<NgxMaskConfig['keepCharacterPositions'] | null>(null);\n public instantPrefix = input<NgxMaskConfig['instantPrefix'] | null>(null);\n // Read directly at blur time (signal is always current) and falls back to the DI\n // config, so no ngOnChanges mirroring into the service is needed (#1435).\n public defaultValueOnBlur = input<NgxMaskConfig['defaultValueOnBlur']>(null);\n\n /**\n * Signal Forms `FormValueControl` surface. At runtime `FormField` never drives this model\n * when the directive is bound (it prefers the `NG_VALUE_ACCESSOR` provided above, see\n * `_isCvaMode`), but the template type-checker treats any directive owning a `value` model\n * as the field's custom control and checks the bound field's value type against it (#1640).\n * The model therefore accepts exactly what `writeValue()` accepts — `string | number | null |\n * undefined` — so numeric and nullable fields (`signal({ amount: 0 })`,\n * `signal<number | null>(null)`, `signal<string | null>(null)`) compile under\n * `strictTemplates`. Values pushed back into the model are always the unmasked string (see\n * `_propagateToValueModel`), i.e. `value()` / `valueChange` are declared wider than what is\n * emitted.\n */\n public value = model<string | number | null | undefined>('');\n public disabled = input(false, { transform: booleanAttribute });\n public touched = model<boolean>(false);\n\n public maskFilled = output<void>();\n\n private _maskValue = signal<string>('');\n private _inputValue = signal<string>('');\n private _code = signal<string>('');\n private _maskExpressionArray = signal<string[]>([]);\n private _justPasted = signal<boolean>(false);\n /** For IME composition event */\n private _isComposing = signal<boolean>(false);\n /**\n * True once Angular has driven this directive through the `ControlValueAccessor` contract\n * (`registerOnChange`). NOTE: Signal Forms' `FormField` ALSO takes this path — it prefers a\n * host-provided `NG_VALUE_ACCESSOR` over the custom-control `value` model binding (see\n * `FormField.ɵngControlCreate`), so it calls `registerOnChange`/`writeValue` too and this\n * flag is `true` in both modes. That is fine: with the flag set, the `value`-model effect\n * below is a no-op and all rendering goes through `writeValue()`. The `value` model is only\n * driven directly (flag stays `false`) when the directive is used standalone with a\n * `[(value)]` binding and no forms integration.\n */\n private _isCvaMode = signal<boolean>(false);\n /** Guards against the value effect echoing back a value we just propagated ourselves. */\n private _skipNextValueEffect = signal<boolean>(false);\n /**\n * The exact stringified value last pushed through `onChange` (view → model). Signal Forms'\n * `FormField` echoes every model update back through `writeValue()` — including updates that\n * originated from the view. Re-masking that unmasked echo is at best a redundant re-render\n * and at worst destructive for masks whose unmasked form is ambiguous (e.g. IP:\n * '192168178' cannot reconstruct the typed dots of '192.168.1.78'). `writeValue()` consumes\n * this marker to skip exactly that echo; ngOnChanges reads it to recognise a `[value]`\n * binding echo of it (#1671). `null` = no pending propagation.\n */\n private _lastPropagatedValue: string | null = null;\n /**\n * The raw control value `writeValue` is currently applying, `null` outside a write. The mask's own\n * `onChange` echo is skipped when it carries exactly this value (the mask left it unchanged);\n * an echo that differs (a normalised or re-typed value) still reaches the form.\n */\n private _writtenValue: { value: unknown } | null = null;\n /**\n * Counts the values put into the input: each `writeValue` that reached the rendering step and\n * each user edit. A write whose masked echo makes a `valueChanges` subscriber call `setValue`\n * again is superseded by that nested write; the outer one compares this counter and leaves the\n * DOM to the latest write (#1691). The deferred leadZero pass of a write compares it as well, so\n * it never re-applies the written value over a newer write or a user edit.\n */\n private _writeSequence = 0;\n /**\n * True while the directive renders a value the user did not type: a `writeValue`, its deferred\n * leadZero pass, a separator change re-rendering the number, a default applied on blur. A model\n * update the mask derives from such a write goes straight to the control without dirtying it\n * (see `_emitProgrammaticValue`).\n */\n private _programmaticWrite = false;\n /**\n * The value the edit currently handled by `onInput` pushed through `onChange`, `null` while it\n * pushed nothing. Read right after the edit to decide `maskFilled`.\n */\n private _valuePropagatedByEdit: string | null = null;\n /**\n * True once the first `ngOnChanges` pass has applied the mask configuration to the service.\n * Signal Forms' `FormField` syncs its field value through the template `ɵɵcontrol` update\n * instruction, which runs BEFORE the sibling directives' first `ngOnChanges` on the same\n * element — so the very first `writeValue()` would otherwise see an unconfigured service\n * (empty `maskExpression`, default `leadZero`/`thousandSeparator`/...) and render the raw\n * value. Until this flag is set, `writeValue()` stashes the incoming value and `ngOnChanges`\n * replays it once the configuration is in place.\n */\n private _configApplied = false;\n private _pendingInitialValue: unknown;\n private _hasPendingInitialValue = false;\n /**\n * True once the `disabled` input has ever delivered `true`. The disabled effect's very\n * first run fires with the input's default `false` even when nothing binds `[disabled]`.\n * Because effects run after Angular Forms' `setUpControl` (which calls\n * `setDisabledState(true)` for initially-disabled controls) and both DOM writes are\n * queueMicrotask-deferred in FIFO order, forwarding that default `false` would land last\n * and re-enable an initially-disabled control (#1607, #1614). An initial `false` write is\n * never needed — inputs are enabled by default — so `false` is only forwarded after the\n * input has explicitly driven the state to `true` at least once.\n */\n private _disabledEverSet = false;\n /** Ensures the multi-character placeHolderCharacter warning (#1347) is emitted only once. */\n private _warnedAboutMultiCharPlaceholder = false;\n\n public _maskService = inject(NgxMaskService, { self: true });\n protected _config = inject<NgxMaskConfig>(NGX_MASK_CONFIG);\n /**\n * `specialCharacters` and `decimalMarker` as bound (the config values when unbound). The\n * service derives working values from them for the current configuration (the minus\n * `allowNegativeNumbers` keeps, the markers a separator mask drops, the comma a dot\n * thousandSeparator forces), so a runtime reconfiguration starts again from these instead of\n * piling the previous configuration's reductions up.\n */\n private readonly _boundConfig: Pick<NgxMaskConfig, 'specialCharacters' | 'decimalMarker'> = {\n specialCharacters: this._config.specialCharacters,\n decimalMarker: this._config.decimalMarker,\n };\n /**\n * Under zoneless change detection, writing to the underlying FormControl programmatically\n * (e.g. `setValue`/`patchValue` from outside a signal/effect context, or from a callback\n * zone.js used to auto-flush like a deferred render callback or `queueMicrotask`) does not itself\n * trigger a CD run. Bindings that read `form.pristine`/`form.dirty`/`form.value` on the host\n * template need an explicit `markForCheck()` once the directive finishes reacting to a\n * programmatic value write, otherwise the view stays stale until something else schedules CD.\n */\n private readonly _changeDetectorRef = inject(ChangeDetectorRef);\n private readonly _elementRef = inject<ElementRef<HTMLInputElement>>(ElementRef);\n private readonly _renderer = inject(Renderer2);\n\n // Injector is used to lazily resolve NgControl. NgControl cannot be injected directly:\n // this directive is registered as the control's NG_VALUE_ACCESSOR, so a direct\n // inject(NgControl) would form a circular dependency. Resolving it lazily on first use\n // (after the control graph is wired) sidesteps the cycle.\n private readonly _injector = inject(Injector);\n // Render hooks run outside the Angular zone; the deferred work below re-enters it so zone.js\n // apps still get change detection for the emissions it triggers.\n private readonly _ngZone = inject(NgZone);\n\n private _ngControl: NgControl | null | undefined;\n\n /**\n * The nearest NgControl: the element's own, else the one bound to an enclosing custom control.\n * Only read from the `registerOnChange` callback, i.e. once a control was handed this\n * directive's accessor contract — directly, or forwarded by a wrapper whose control is then\n * the nearest one. A wrapper that implements the contract itself never registers with the\n * mask, so the mask never writes to that wrapper's control.\n */\n private _resolveNgControl(): NgControl | null {\n if (typeof this._ngControl === 'undefined') {\n this._ngControl = this._injector.get(NgControl, null);\n }\n return this._ngControl;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n public onChange = (_: unknown) => {};\n\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n public onTouch = () => {};\n\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n private _onValidatorChange = () => {};\n\n public constructor() {\n // Default onChange used in Signal Forms mode, where Angular never calls registerOnChange.\n // It pushes the unmasked value into the `value` model so the `valueChange` output fires.\n // registerOnChange() overrides this to additionally invoke Angular's CVA callback.\n this._maskService.onChange = this.onChange = (value: unknown) => {\n this._propagateToValueModel(value);\n };\n\n // Signal Forms drives the `value` model input directly (custom-control mode).\n // In classic CVA mode `writeValue` handles rendering instead, so this effect is a no-op\n // there. We skip the pass immediately following our own onChange propagation to avoid\n // clobbering the raw `_inputValue` with the masked value echoed back from the model.\n effect(() => {\n const signalValue = this.value();\n untracked(() => {\n if (this._valueEffectWillWrite(signalValue)) {\n this.writeValue(signalValue);\n } else {\n this._skipNextValueEffect.set(false);\n }\n });\n });\n\n effect(() => {\n const isDisabled = this.disabled();\n untracked(() => {\n // Never force-enable on the default `false`: it would clobber Angular Forms'\n // own setDisabledState(true) for initially-disabled controls (see\n // _disabledEverSet). `false` is forwarded only after an explicit `true`.\n if (!isDisabled && !this._disabledEverSet) {\n return;\n }\n this._disabledEverSet = true;\n this.setDisabledState(isDisabled);\n });\n });\n }\n\n public ngOnChanges(changes: SimpleChanges): void {\n const {\n mask,\n specialCharacters,\n patterns,\n prefix,\n suffix,\n thousandSeparator,\n decimalMarker,\n dropSpecialCharacters,\n hiddenInput,\n showMaskTyped,\n placeHolderCharacter,\n clearIfNotMatch,\n validation,\n allowNegativeNumbers,\n apm,\n } = changes;\n const previousSeparators = {\n thousandSeparator: this._maskService.thousandSeparator,\n decimalMarker: this._maskService.decimalMarker,\n prefix: this._maskService.prefix,\n suffix: this._maskService.suffix,\n };\n if (mask) {\n if (mask.currentValue !== mask.previousValue && !mask.firstChange) {\n this._maskService.maskChanged = true;\n }\n // User-defined aliases (config maskAliases) expand BEFORE any other processing,\n // including the `||` multi-mask split — an alias may expand to a multi-mask.\n const resolvedMask = this._resolvedMaskInput();\n const maskParts = resolvedMask.split(MaskExpression.OR);\n if (maskParts.length > 1) {\n this._maskExpressionArray.set(\n maskParts.sort((a: string, b: string) => a.length - b.length)\n );\n this._setMask();\n } else {\n this._maskExpressionArray.set([]);\n this._maskValue.set(resolvedMask);\n this._maskService.maskExpression = this._maskValue();\n }\n }\n if (specialCharacters) {\n if (Array.isArray(specialCharacters.currentValue)) {\n this._boundConfig.specialCharacters = specialCharacters.currentValue;\n this._maskService.specialCharacters = specialCharacters.currentValue;\n }\n // A non-array value (e.g. null from an unset dynamic config) keeps the current\n // service value (config defaults) and must not abort the whole ngOnChanges pass,\n // otherwise sibling inputs changed in the same cycle would be silently ignored (#1512).\n }\n if (allowNegativeNumbers) {\n this._maskService.allowNegativeNumbers = allowNegativeNumbers.currentValue;\n this._keepMinusOutOfSpecialCharacters();\n }\n // Only overwrite the mask available patterns if a pattern has actually been passed in\n if (patterns && patterns.currentValue) {\n this._maskService.patterns = patterns.currentValue;\n }\n if (apm) {\n // A falsy value (`false`) must be mirrored too, otherwise it cannot override a global\n // `apm: true` or switch the option off at runtime; `null` means \"unset\" -> config.\n this._maskService.apm = apm.currentValue ?? this._config.apm;\n }\n\n if (decimalMarker) {\n this._boundConfig.decimalMarker = decimalMarker.currentValue;\n }\n if (thousandSeparator) {\n this._maskService.thousandSeparator = thousandSeparator.currentValue;\n if (thousandSeparator.previousValue && thousandSeparator.currentValue) {\n // The marker the previous separator forced (a dot thousandSeparator turns '.'\n // into ',') is not the bound one: start from the bound marker again.\n this._maskService.decimalMarker = this._boundConfig.decimalMarker;\n if (thousandSeparator.currentValue === this._maskService.decimalMarker) {\n this._maskService.decimalMarker =\n thousandSeparator.currentValue === MaskExpression.COMMA\n ? MaskExpression.DOT\n : MaskExpression.COMMA;\n }\n this._maskService.writingValue = true;\n }\n }\n if (hiddenInput) {\n this._maskService.hiddenInput = hiddenInput.currentValue;\n if (hiddenInput.previousValue === true && hiddenInput.currentValue === false) {\n this._inputValue.set(this._maskService.actualValue);\n }\n }\n if (showMaskTyped) {\n this._maskService.showMaskTyped = showMaskTyped.currentValue;\n if (\n showMaskTyped.previousValue === false &&\n showMaskTyped.currentValue === true &&\n this._maskService._isFocused()\n ) {\n afterNextRender(\n () => {\n // The render hook fires before the microtask that writes the mask\n // skeleton (formElementProperty); click after it so onClick sees it.\n queueMicrotask(() =>\n this._ngZone.run(() => {\n this._maskService._elementRef?.nativeElement.click();\n })\n );\n },\n { injector: this._injector }\n );\n }\n }\n if (placeHolderCharacter) {\n // `null`/`undefined` means \"no custom placeholder\" (#1643): fall back to the default\n // instead of storing null, which broke every `.length` read on the service.\n this._maskService.placeHolderCharacter =\n placeHolderCharacter.currentValue ?? this._config.placeHolderCharacter;\n if (\n typeof placeHolderCharacter.currentValue === 'string' &&\n placeHolderCharacter.currentValue.length > 1 &&\n !this._warnedAboutMultiCharPlaceholder\n ) {\n this._warnedAboutMultiCharPlaceholder = true;\n // eslint-disable-next-line no-console\n console.warn(\n 'Ngx-mask: placeHolderCharacter should be a single character; behavior with multi-character values is undefined (e.g. keepCharacterPositions will not work). Current value:',\n placeHolderCharacter.currentValue\n );\n }\n }\n const specialCharactersSources = [\n mask,\n specialCharacters,\n allowNegativeNumbers,\n thousandSeparator,\n decimalMarker,\n dropSpecialCharacters,\n ];\n // A switch to no mask is neutral: the raw-value revert of the empty mask (applyMask's\n // maskChanged branch) strips with the working set of the mask the value was produced by\n // (a separator mask keeps its markers out of it), so the rebuild from the bound values\n // waits for the next mask.\n if (\n this._maskValue() &&\n specialCharactersSources.some((change) => change && !change.firstChange)\n ) {\n this._maskService.specialCharacters = this._boundConfig.specialCharacters;\n this._keepMinusOutOfSpecialCharacters();\n }\n // Pure mirrors: runs after every explicit block above (a bound decimalMarker wins over the\n // one the thousandSeparator block derives) and before `_applyMask`.\n for (const key of MIRRORED_INPUTS) {\n const change = changes[key];\n if (change) {\n this._mirrorInput(key, change.currentValue);\n }\n }\n const retargetSeparators =\n (thousandSeparator || decimalMarker) &&\n this._configApplied &&\n this._maskValue().startsWith(MaskExpression.SEPARATOR) &&\n this._inputValue();\n if (retargetSeparators) {\n // The rendered number still uses the previous markers: carry it over to the new ones\n // before the mask re-reads it, or its old decimal marker becomes a thousand separator.\n this._inputValue.set(\n retargetSeparatorValue(this._inputValue(), previousSeparators, this._maskService)\n );\n this._maskService.actualValue = this._inputValue();\n this._maskService.writingValue = true;\n // The re-render below carries the number over to the new markers: what an earlier\n // write still has deferred (the leadZero pass) holds it in the old ones.\n this._writeSequence++;\n }\n // #1671: a standalone `[(value)]` change reaches ngOnChanges BEFORE the value effect\n // writes it, so `_inputValue` still holds the PREVIOUS value here. Re-rendering it would\n // run applyMask on stale input, and whatever that emits (the showMaskTyped skeleton's\n // '', a hiddenInput / keepCharacterPositions reconstruction) flows back through onChange,\n // overwrites the freshly bound model and makes the effect skip the real write. When the\n // effect is about to render the new value via writeValue() anyway, only apply the mask\n // configuration here. The effect only runs when the `value` SIGNAL changes: a parent\n // re-binding the value we last propagated (an echo, possibly applied in a later task)\n // changes the binding but not the signal, which already holds it — that pass renders.\n const valueChange = changes['value'];\n const valueEffectWillRender =\n !!valueChange &&\n String(valueChange.currentValue) !== this._lastPropagatedValue &&\n this._valueEffectWillWrite(valueChange.currentValue);\n if (retargetSeparators && !this._maskService.maskChanged) {\n // Re-rendering the same number in the new markers is no user edit. A mask changed in\n // the same pass makes this render the triggerOnMaskChange emission instead, which\n // dirties the control like any other.\n this._writeProgrammatically(() => this._applyMask(!valueEffectWillRender));\n } else {\n this._applyMask(!valueEffectWillRender);\n }\n // `validate` reads these fields: Angular must re-run the validator, otherwise the\n // control keeps the verdict computed for the previous configuration until the next edit.\n // The first binding is skipped — the control validates itself when it is set up.\n const validationInputChanges = [\n mask,\n validation,\n patterns,\n prefix,\n suffix,\n dropSpecialCharacters,\n specialCharacters,\n clearIfNotMatch,\n ];\n // Runs after `_applyMask`: the verdict also reads state the mask pass derives\n // (`ipError`, `cpfCnpjError`), which must already describe the new configuration.\n if (validationInputChanges.some((change) => change && !change.firstChange)) {\n this._onValidatorChange();\n }\n if (!this._configApplied) {\n this._configApplied = true;\n if (this._hasPendingInitialValue) {\n // Replay the writeValue() call that arrived before this first ngOnChanges pass\n // (see _configApplied) now that the mask configuration is applied.\n this._hasPendingInitialValue = false;\n const pendingValue = this._pendingInitialValue;\n this._pendingInitialValue = null;\n this.writeValue(pendingValue);\n }\n }\n }\n\n /** With `allowNegativeNumbers` the minus is part of the number, never a character to drop. */\n private _keepMinusOutOfSpecialCharacters(): void {\n if (this._maskService.allowNegativeNumbers) {\n this._maskService.specialCharacters = this._maskService.specialCharacters.filter(\n (c: string) => c !== MaskExpression.MINUS\n );\n }\n }\n\n public validate({ value }: FormControl): ValidationErrors | null {\n return this._validateValue(value).errors;\n }\n\n /**\n * The validation verdict for `value`. `filled` is true when the value passed every check and\n * reached the end of the rules: a non-empty value that satisfies the mask. `maskFilled` is\n * derived from it after a user edit; the validator itself must stay side-effect free.\n */\n private _validateValue(value: FormControl['value']): {\n errors: ValidationErrors | null;\n filled: boolean;\n } {\n const processedValue: string = typeof value === 'number' ? String(value) : value;\n const maskValue = this._maskValue();\n\n if (!this._maskService.validation || !maskValue) {\n return notFilled(null);\n }\n // The IP / CPF verdicts are only written by their own handlers, so after a runtime mask\n // switch the last one is stale: honour it only while its mask is the active one.\n const isCpfCnpj =\n maskValue === MaskExpression.CPF_CNPJ || maskValue === MaskExpression.CPF_CNPJ_ALPHA;\n if (maskValue === MaskExpression.IP && this._maskService.ipError) {\n return notFilled(this._createValidationError(processedValue));\n }\n if (isCpfCnpj && this._maskService.cpfCnpjError) {\n return notFilled(this._createValidationError(processedValue));\n }\n if (maskValue.startsWith(MaskExpression.SEPARATOR)) {\n return notFilled(null);\n }\n if (withoutValidation.includes(maskValue)) {\n return notFilled(null);\n }\n if (this._maskService.clearIfNotMatch) {\n return notFilled(null);\n }\n if (timeMasks.includes(maskValue)) {\n return notFilled(this._validateTime(processedValue));\n }\n if (maskValue === MaskExpression.EMAIL_MASK) {\n const emailPattern = /^[^@]+@[^@]+\\.[^@]+$/;\n\n if (!emailPattern.test(processedValue) && processedValue) {\n return notFilled(this._createValidationError(processedValue));\n } else {\n return notFilled(null);\n }\n }\n if (processedValue && processedValue.length >= 1) {\n let counterOfOpt = 0;\n\n if (\n maskValue.includes(MaskExpression.CURLY_BRACKETS_LEFT) &&\n maskValue.includes(MaskExpression.CURLY_BRACKETS_RIGHT)\n ) {\n const lengthInsideCurlyBrackets = maskValue.slice(\n maskValue.indexOf(MaskExpression.CURLY_BRACKETS_LEFT) + 1,\n maskValue.indexOf(MaskExpression.CURLY_BRACKETS_RIGHT)\n );\n\n return notFilled(\n lengthInsideCurlyBrackets === String(processedValue.length)\n ? null\n : this._createValidationError(processedValue)\n );\n }\n if (maskValue.startsWith(MaskExpression.PERCENT)) {\n return notFilled(null);\n }\n for (const key in this._maskService.patterns) {\n if (this._maskService.patterns[key]?.optional) {\n if (maskValue.indexOf(key) !== maskValue.lastIndexOf(key)) {\n const opt: string = maskValue\n .split(MaskExpression.EMPTY_STRING)\n .filter((i: string) => i === key)\n .join(MaskExpression.EMPTY_STRING);\n counterOfOpt += opt.length;\n } else if (maskValue.indexOf(key) !== -1) {\n counterOfOpt++;\n }\n const firstOptionalIndex = maskValue.indexOf(key);\n if (firstOptionalIndex !== -1 && processedValue.length >= firstOptionalIndex) {\n // #1515: the early \"everything before the first optional token is\n // filled\" return is only sound for trailing-optional layouts. When a\n // mandatory token follows the first optional one (e.g. `999SSS`,\n // indexOf === 0) it used to mark EVERY value as valid.\n const hasMandatoryAfterOptional = maskValue\n .slice(firstOptionalIndex)\n .split(MaskExpression.EMPTY_STRING)\n .some(\n (symbol: string) =>\n !!this._maskService.patterns[symbol] &&\n !this._maskService.patterns[symbol]?.optional\n );\n if (!hasMandatoryAfterOptional) {\n return notFilled(null);\n }\n if (\n !this._maskService.prefix &&\n !this._maskService.suffix &&\n this._isPlainTokenMask(maskValue)\n ) {\n // Position-aware check: match the value against the mask allowing\n // optional tokens to be skipped; every mandatory token must be\n // consumed (catches `12a` for `999SSS`, which a pure length\n // check cannot).\n return notFilled(\n this._matchesMaskWithOptionalSkip(processedValue, maskValue)\n ? null\n : this._createValidationError(processedValue)\n );\n }\n // Non-plain masks (prefix/suffix, exotic symbols) fall through to the\n // legacy length check below (`maskValue.length - counterOfOpt`).\n }\n if (counterOfOpt === maskValue.length) {\n return notFilled(null);\n }\n }\n }\n if (\n (maskValue.indexOf(MaskExpression.SYMBOL_STAR) > 1 &&\n processedValue.length < maskValue.indexOf(MaskExpression.SYMBOL_STAR)) ||\n (maskValue.indexOf(MaskExpression.SYMBOL_QUESTION) > 1 &&\n processedValue.length < maskValue.indexOf(MaskExpression.SYMBOL_QUESTION))\n ) {\n return notFilled(this._createValidationError(processedValue));\n }\n if (\n maskValue.indexOf(MaskExpression.SYMBOL_STAR) === -1 ||\n maskValue.indexOf(MaskExpression.SYMBOL_QUESTION) === -1\n ) {\n const array = maskValue.split('*');\n const length: number = this._maskService.dropSpecialCharacters\n ? maskValue.length -\n this._maskService.checkDropSpecialCharAmount(maskValue) -\n counterOfOpt\n : this._maskService.prefix\n ? maskValue.length + this._maskService.prefix.length - counterOfOpt\n : maskValue.length - counterOfOpt;\n\n if (array.length === 1) {\n if (processedValue.length < length) {\n // #1583: for `||` multi-masks, a value shorter than the selected\n // alternative can still be complete: it must stop exactly at a\n // special-character boundary of the selected alternative and satisfy\n // the length requirement of another (shorter) alternative.\n if (this._isCompleteAlternativeBoundary(processedValue)) {\n return notFilled(null);\n }\n return notFilled(this._createValidationError(processedValue));\n }\n }\n if (array.length > 1) {\n const lastIndexArray = array[array.length - 1];\n if (\n lastIndexArray &&\n this._maskService.specialCharacters.includes(lastIndexArray[0] as string) &&\n String(processedValue).includes(lastIndexArray[0] ?? '') &&\n !this._maskService.dropSpecialCharacters\n ) {\n const special = processedValue.split(lastIndexArray[0] as string);\n return notFilled(\n special[special.length - 1]?.length === lastIndexArray.length - 1\n ? null\n : this._createValidationError(processedValue)\n );\n } else if (\n ((lastIndexArray &&\n !this._maskService.specialCharacters.includes(\n lastIndexArray[0] as string\n )) ||\n !lastIndexArray ||\n this._maskService.dropSpecialCharacters) &&\n processedValue.length >= length - 1\n ) {\n return notFilled(null);\n } else {\n return notFilled(this._createValidationError(processedValue));\n }\n }\n }\n if (\n maskValue.indexOf(MaskExpression.SYMBOL_STAR) === 1 ||\n maskValue.indexOf(MaskExpression.SYMBOL_QUESTION) === 1\n ) {\n return notFilled(null);\n }\n }\n return { errors: null, filled: !!value };\n }\n\n public onPaste() {\n this._justPasted.set(true);\n }\n\n public onFocus(): void {\n this._maskService._isFocused.set(true);\n }\n\n public onModelChange(value: unknown): void {\n // on form reset we need to update the actualValue\n if (\n (value === MaskExpression.EMPTY_STRING ||\n value === null ||\n typeof value === 'undefined') &&\n this._maskService.actualValue\n ) {\n this._maskService.actualValue = this._maskService.getActualValue(\n MaskExpression.EMPTY_STRING\n );\n }\n }\n\n public onInput(e: Event): void {\n // A user edit supersedes what an earlier write still has deferred (see _writeSequence).\n this._writeSequence++;\n this._valuePropagatedByEdit = null;\n this._processInput(e);\n // `maskFilled` reports a mask completed by the user, so it is decided here, once per\n // edit, from the value this edit pushed to the model. It must not live in the validator:\n // that also runs for every programmatic write and every revalidation.\n const propagated = this._valuePropagatedByEdit;\n this._valuePropagatedByEdit = null;\n if (propagated !== null && this._validateValue(propagated).filled) {\n this.maskFilled.emit();\n }\n }\n\n /** `insertText`-style input event carrying more than one character (composition excluded). */\n private _isBulkInsertion(e: Event): boolean {\n const { inputType, data } = e as InputEvent;\n return (\n typeof inputType === 'string' &&\n inputType.startsWith('insert') &&\n inputType !== 'insertCompositionText' &&\n typeof data === 'string' &&\n data.length > 1\n );\n }\n\n /**\n * Whether nothing the user entered follows the caret, i.e. the edit ended the value. Only\n * the suffix and the untouched skeleton of a showMaskTyped / keepCharacterPositions field\n * (special and placeholder characters) may still follow it.\n */\n private _editEndsValue(el: HTMLInputElement): boolean {\n return !this._maskService.removeMask(el.value.slice(el.selectionEnd ?? el.value.length));\n }\n\n private _processInput(e: Event): void {\n this._maskService.isInitialized = true;\n // The value the keydown of this edit saw; `_inputValue` is overwritten with the edited one below.\n const preEditValue = this._inputValue();\n // Android IMEs report every keydown as key 'Unidentified' / keyCode 229, so a\n // backspace is undetectable from keydown alone and all _code()-based deletion\n // branches misfire (cursor jumps, \"stuck\" backspace — #1497). The input event's\n // inputType is the reliable source: derive the deletion code from it.\n const inputType: string | undefined = (e as InputEvent).inputType;\n if (inputType === 'deleteContentBackward') {\n this._code.set(MaskExpression.BACKSPACE);\n } else if (inputType === 'deleteContentForward') {\n this._code.set(MaskExpression.DELETE);\n } else if (\n inputType &&\n (this._code() === MaskExpression.BACKSPACE || this._code() === MaskExpression.DELETE)\n ) {\n // A non-delete edit that produced no meaningful keydown (IME insertion,\n // context-menu paste): clear the stale deletion code so the edit is not\n // processed as a backspace.\n this._code.set(inputType);\n }\n // If IME is composing text, we wait for the composed text — but only when the mask\n // can actually accept letters. Purely numeric masks gain nothing from composition,\n // and some Android IMEs (Samsung Keyboard) deliver every keystroke as\n // insertCompositionText without firing compositionend until blur, which would leave\n // the FormControl stale for the whole edit (#1293).\n if (this._isComposing() && this._maskAcceptsLetterInput()) {\n return;\n }\n const el: HTMLInputElement = (e as InputEvent).target as HTMLInputElement;\n\n const transformedValue = this._maskService.inputTransformFn\n ? this._maskService.inputTransformFn(el.value)\n : el.value;\n\n if (el.type !== 'number') {\n if (typeof transformedValue === 'string' || typeof transformedValue === 'number') {\n const transformedString = transformedValue.toString();\n // Only rewrite el.value when the transform actually changed it: any\n // programmatic `.value =` assignment clears the browser's \"last changed\n // by a user edit\" flag, which silently disables native constraint\n // validation (minlength -> validity.tooShort) even when the mask is a\n // no-op (#1379). With an empty mask the directive must stay a pure\n // passthrough for the native input.\n if (el.value !== transformedString) {\n el.value = transformedString;\n }\n\n this._inputValue.set(el.value);\n this._setMask();\n\n if (!this._maskValue()) {\n this.onChange(el.value);\n return;\n }\n\n // A whole string inserted by ONE edit (autofill, a drop, a speech or\n // clipboard-style IME insertion, the Browser pane's insertText) is a paste: it\n // arrives as a bare run of characters, not as a keystroke on top of the already\n // masked value, and fires no `paste` event. Only when the run ends the value,\n // though: the paste path puts the caret at the end of the value, which is wrong\n // for a run inserted (dictation, a spellcheck or predictive replacement) in the\n // middle of it — that edit keeps the keystroke path and its caret.\n if (this._isBulkInsertion(e) && this._editEndsValue(el)) {\n this._justPasted.set(true);\n }\n\n // On paste of a raw value that does not yet carry the prefix, the caret\n // position reported by the element is prefix.length short of where it must\n // land once applyMask prepends the prefix (#1571). Captured here because the\n // applyValueChanges callback below resets the _justPasted flag.\n const pastedValueWithoutPrefix =\n this._justPasted() &&\n !!this._maskService.prefix &&\n !el.value.startsWith(this._maskService.prefix);\n\n const caret = el.selectionStart as number;\n let position: number =\n el.selectionStart === 1\n ? (el.selectionStart as number) + this._maskService.prefix.length\n : (el.selectionStart as number);\n\n if (\n this._maskService.keepCharacterPositions &&\n this._maskService.placeHolderCharacter.length === 1 &&\n !this._justPasted()\n ) {\n const kcp = resolveKeepCharacterPositions(this._maskService, {\n elValue: el.value,\n position,\n code: this._code(),\n before: preEditValue,\n });\n if (kcp.actualValue !== null) {\n this._maskService.actualValue = kcp.actualValue;\n }\n position = kcp.position;\n // Whether the resolution fully rendered the display value into actualValue\n // (applyMask then short-circuits), or the edit flows through regular masking.\n this._maskService.keepCharacterPositionsHandled = kcp.handled;\n }\n\n // A literal '*' typed into the VALUE (custom pattern allowing asterisks) makes\n // the service's applyMask take its hiddenInput shadow-value branch, whose\n // equal/shorter-length cases restore the stale pre-edit actualValue and discard\n // a selection replacement (#1504). Without hiddenInput there is no shadow state\n // to preserve, so drop it and let the edited value flow through regular masking.\n if (\n !this._maskService.hiddenInput &&\n !this._maskService.showMaskTyped &&\n !this._maskService.keepCharacterPositions &&\n this._maskService.selStart !== this._maskService.selEnd &&\n containsStarSymbol(\n el.value,\n this._maskService.maskExpression,\n this._maskService.thousandSeparator\n )\n ) {\n this._maskService.actualValue = MaskExpression.EMPTY_STRING;\n }\n\n let caretShift = 0;\n let backspaceShift = false;\n const isDeletion =\n this._code() === MaskExpression.BACKSPACE ||\n this._code() === MaskExpression.DELETE;\n if (this._code() === MaskExpression.DELETE) {\n this._maskService.deletedSpecialCharacter = true;\n }\n // A paste, a prefix, suffix, keepCharacterPositions or hiddenInput mask and any\n // typed edit overwriteDateSlot declines keep the older d0/M0/0000 overwrite.\n const keepsFullDateOverwrite =\n this._justPasted() ||\n this._maskService.prefix ||\n this._maskService.suffix ||\n this._maskService.keepCharacterPositions ||\n this._maskService.hiddenInput;\n const overwrite =\n keepsFullDateOverwrite || isDeletion\n ? null\n : overwriteDateSlot(this._maskService, preEditValue, el.value, position);\n if (overwrite) {\n el.value = overwrite.value;\n this._inputValue.set(overwrite.value);\n position = overwrite.position;\n } else if (keepsFullDateOverwrite || !isDeletion) {\n const overwrittenDate = overwriteFullDateValue(\n this._maskService.maskExpression,\n this._inputValue(),\n position,\n this._code()\n );\n if (overwrittenDate !== null) {\n el.value = overwrittenDate;\n }\n }\n if (this._maskService.leadZeroDateTime) {\n // The edit touches the characters next to the caret; a paste touches them all.\n // A deletion that starts on a separator changes no field next to the caret, so\n // it leaves nothing to clamp.\n const removedChar = isDeletion\n ? (preEditValue[caret] ?? MaskExpression.EMPTY_STRING)\n : MaskExpression.EMPTY_STRING;\n setUserEdit(\n this._maskService,\n this._maskService.specialCharacters.includes(removedChar)\n ? null\n : {\n value: el.value,\n start: this._justPasted() ? 0 : caret - 1,\n end: this._justPasted()\n ? el.value.length\n : (overwrite?.end ?? caret),\n }\n );\n position = leadZeroDateTimeCaret(\n this._maskService.maskExpression,\n position,\n el.value,\n this._inputValue(),\n !!this._maskService.apm\n );\n }\n\n this._maskService.applyValueChanges(\n position,\n this._justPasted(),\n isDeletion,\n (shift: number, _backspaceShift: boolean) => {\n this._justPasted.set(false);\n caretShift = shift;\n backspaceShift = _backspaceShift;\n }\n );\n // The edit is masked; no later render of the same value is an edit.\n setUserEdit(this._maskService, null);\n // only set the selection if the element is active\n if (this._maskService._getActiveElement() !== el) {\n return;\n }\n\n if (this._maskService.plusOnePosition) {\n position = position + 1;\n this._maskService.plusOnePosition = false;\n }\n // update position after applyValueChanges to prevent cursor on wrong position when it has an array of maskExpression\n if (this._maskExpressionArray().length) {\n if (this._code() === MaskExpression.BACKSPACE) {\n const specialChartMinusOne = this._maskService.specialCharacters.includes(\n this._maskService.actualValue.slice(position - 1, position)\n );\n const allowFewMaskChangeMask =\n this._maskService.removeMask(this._inputValue())?.length ===\n this._maskService.removeMask(this._maskService.maskExpression)?.length;\n\n const specialChartPlusOne = this._maskService.specialCharacters.includes(\n this._maskService.actualValue.slice(position, position + 1)\n );\n if (allowFewMaskChangeMask && !specialChartPlusOne) {\n position = (el.selectionStart as number) + 1;\n } else {\n position = specialChartMinusOne ? position - 1 : position;\n }\n } else {\n position =\n el.selectionStart === 1\n ? (el.selectionStart as number) + this._maskService.prefix.length\n : (el.selectionStart as number);\n }\n }\n let positionToApply: number =\n position +\n (this._code() === MaskExpression.BACKSPACE && !backspaceShift ? 0 : caretShift);\n // For separator masks the applier's caret shift is computed on the raw\n // (prefix-less) value, so account for the prefix the mask just added (#1571).\n if (\n pastedValueWithoutPrefix &&\n this._maskValue().startsWith(MaskExpression.SEPARATOR)\n ) {\n positionToApply += this._maskService.prefix.length;\n }\n if (positionToApply > this._getActualInputLength()) {\n // A bare decimal marker ('.' or, with a prefix, '$.') is not a number:\n // formControlResult has just emitted null for it, which the ngModelChange\n // reset handler treats as a form reset and clears actualValue. The plain\n // length clamp would then land the caret BEFORE the marker — keep it right\n // after the marker instead (#1572).\n const decimalMarker = this._maskService.decimalMarker;\n const prefix = this._maskService.prefix;\n const valueWithoutPrefix = el.value.startsWith(prefix)\n ? el.value.slice(prefix.length)\n : el.value;\n const isBareDecimalMarker =\n valueWithoutPrefix.length === 1 &&\n (Array.isArray(decimalMarker)\n ? decimalMarker.includes(\n valueWithoutPrefix as MaskExpression.DOT | MaskExpression.COMMA\n )\n : valueWithoutPrefix === decimalMarker);\n positionToApply = isBareDecimalMarker\n ? this._getActualInputLength() + 1\n : this._getActualInputLength();\n }\n if (positionToApply < 0) {\n positionToApply = 0;\n }\n if (el.selectionStart !== positionToApply || el.selectionEnd !== positionToApply) {\n el.setSelectionRange(positionToApply, positionToApply);\n }\n } else {\n // eslint-disable-next-line no-console\n console.warn(\n 'Ngx-mask writeValue work with string | number, your current value:',\n typeof transformedValue\n );\n }\n } else {\n if (!this._maskValue()) {\n this.onChange(el.value);\n return;\n }\n this._maskService.applyValueChanges(\n el.value.length,\n this._justPasted(),\n this._code() === MaskExpression.BACKSPACE || this._code() === MaskExpression.DELETE\n );\n }\n }\n\n /**\n * Whether any pattern slot of the current mask expression can accept a letter.\n * IME composition is only meaningful for such masks; for purely numeric masks\n * (digit patterns, separator, date/time, IP, CPF_CNPJ) waiting for compositionend\n * only delays the model sync — and Samsung Keyboard may never fire it until blur\n * (#1293). Unknown/letterless probe failures fall back to `false` (process live).\n */\n private _maskAcceptsLetterInput(): boolean {\n for (const symbol of this._maskService.maskExpression) {\n if (\n this._maskService._checkSymbolMask('a', symbol) ||\n this._maskService._checkSymbolMask('A', symbol)\n ) {\n return true;\n }\n }\n return false;\n }\n\n // IME starts\n public onCompositionStart(): void {\n this._isComposing.set(true);\n }\n\n // IME completes\n public onCompositionEnd(e: Event): void {\n this._isComposing.set(false);\n if (!this._maskAcceptsLetterInput()) {\n // For letterless masks every edit was already processed live in onInput\n // (#1293); reprocessing the same value through the paste path would\n // double-apply the mask.\n return;\n }\n this._justPasted.set(true);\n this.onInput(e);\n }\n\n public onBlur(e: Event): void {\n if (this._maskValue()) {\n const el: HTMLInputElement = (e as FocusEvent).target as HTMLInputElement;\n if (this._applyDefaultValueOnBlur(el)) {\n // Padding or clearing the default is part of that programmatic write: it must not\n // dirty the control either. Blur still touches it (onTouch below).\n this._writeProgrammatically(() => this._formatOnBlur(el));\n this._changeDetectorRef.markForCheck();\n } else {\n this._formatOnBlur(el);\n }\n }\n this._maskService._isFocused.set(false);\n this.onTouch();\n }\n\n /** The blur-time leadZero padding and clearIfNotMatch pass. */\n private _formatOnBlur(el: HTMLInputElement): void {\n if (\n this._maskService.leadZero &&\n el.value.length > 0 &&\n typeof this._maskService.decimalMarker === 'string'\n ) {\n const maskExpression = this._maskService.maskExpression;\n const decimalMarker = this._maskService.decimalMarker as string;\n const suffix = this._maskService.suffix;\n const precision = Number(\n this._maskService.maskExpression.slice(\n maskExpression.length - 1,\n maskExpression.length\n )\n );\n\n if (precision > 0) {\n const unsuffixedValue = suffix ? el.value.split(suffix).join('') : el.value;\n const decimalPart = unsuffixedValue.split(decimalMarker)[1] as string;\n\n const paddedValue = unsuffixedValue.includes(decimalMarker)\n ? unsuffixedValue +\n MaskExpression.NUMBER_ZERO.repeat(precision - (decimalPart?.length || 0)) +\n suffix\n : unsuffixedValue +\n decimalMarker +\n MaskExpression.NUMBER_ZERO.repeat(precision) +\n suffix;\n // Only a blur that really pads the text is an edit: re-emitting the same\n // text would dirty the control and fire a duplicate valueChanges for a plain\n // focus + blur of a prefilled field.\n if (paddedValue !== el.value) {\n el.value = paddedValue;\n this._maskService.actualValue = el.value;\n // #1634: propagate through the regular formControlResult pipeline (not a\n // raw onChange) so outputTransformFn runs on this blur-time reformat, same\n // as every typing-time emission. A raw onChange here sent the masked\n // display string straight to the model, bypassing outputTransformFn.\n this._maskService.formControlResult(this._maskService.actualValue);\n }\n }\n }\n this._maskService.clearIfNotMatchFn();\n }\n\n /**\n * Issue #1435 (defaultValueOnBlur): when configured — via the directive input or the\n * DI config — and the control's unmasked value is empty on blur (covers '', a bare\n * prefix/suffix and the showMaskTyped skeleton), writes the default through the\n * regular mask pipeline: applyMask renders the masked display and emits the usual\n * model output (dropSpecialCharacters/outputTransformFn applied) via formControlResult.\n * The default is no user edit, so it does not dirty the control. Returns whether a default\n * was applied.\n */\n private _applyDefaultValueOnBlur(el: HTMLInputElement): boolean {\n const defaultValue = this.defaultValueOnBlur() ?? this._config.defaultValueOnBlur;\n if (!defaultValue || this._maskService.removeMask(el.value)) {\n return false;\n }\n const displayValue = this._writeProgrammatically(() =>\n this._maskService.applyMask(defaultValue, this._maskService.maskExpression)\n );\n el.value = displayValue;\n this._inputValue.set(displayValue);\n return true;\n }\n\n public onClick(e: Event): void {\n if (!this._maskValue()) {\n return;\n }\n\n const el: HTMLInputElement = (e as MouseEvent).target as HTMLInputElement;\n\n if (\n el !== null &&\n el.selectionStart !== null &&\n el.selectionStart === el.selectionEnd &&\n el.selectionStart > this._maskService.prefix.length\n ) {\n if (this._maskService.showMaskTyped && !this._maskService.keepCharacterPositions) {\n // We are showing the mask in the input\n this._maskService.maskIsShown = this._maskService.showMaskInInput();\n if (\n el.setSelectionRange &&\n this._maskService.prefix + this._maskService.maskIsShown === el.value\n ) {\n // the input ONLY contains the mask, so position the cursor at the start\n el.focus();\n el.setSelectionRange(0, 0);\n } else {\n // the input contains some characters already\n if (el.selectionStart > this._maskService.actualValue.length) {\n // if the user clicked beyond our value's length, position the cursor at the end of our value\n el.setSelectionRange(\n this._maskService.actualValue.length,\n this._maskService.actualValue.length\n );\n }\n }\n }\n }\n const nextValue: string | null =\n el &&\n (el.value === this._maskService.prefix\n ? this._maskService.prefix + this._maskService.maskIsShown\n : el.value);\n\n /** Fix of cursor position jumping to end in most browsers no matter where cursor is inserted onFocus */\n if (el && el.value !== nextValue) {\n el.value = nextValue;\n }\n /** fix of cursor position with prefix when mouse click occur */\n if (\n el &&\n el.type !== 'number' &&\n ((el.selectionStart as number) || (el.selectionEnd as number)) <=\n this._maskService.prefix.length\n ) {\n const specialCharactersAtTheStart =\n this._maskService.maskExpression.match(\n new RegExp(\n `^[${this._maskService.specialCharacters.map((c) => escapeRegExp(c)).join('')}]+`\n )\n )?.[0].length || 0;\n\n el.selectionStart = this._maskService.prefix.length + specialCharactersAtTheStart;\n return;\n }\n /** select only inserted text */\n if (el && (el.selectionEnd as number) > this._getActualInputLength()) {\n el.selectionEnd = this._getActualInputLength();\n }\n }\n\n public onKeyDown(event: Event): void {\n const e = event as KeyboardEvent;\n if (!this._maskValue()) {\n return;\n }\n\n if (this._isComposing()) {\n // User finalize their choice from IME composition, so trigger onInput() for the composed text.\n if (e.key === 'Enter') {\n this.onCompositionEnd(event);\n return;\n }\n // Android IMEs can keep a single composition open across many keystrokes\n // (#1293): still capture the pre-edit value and selection that onInput\n // relies on when it processes edits during composition.\n const composingEl = e.target as HTMLInputElement;\n this._inputValue.set(composingEl.value);\n this._maskService.selStart = composingEl.selectionStart;\n this._maskService.selEnd = composingEl.selectionEnd;\n return;\n }\n\n this._code.set(e.code ? e.code : e.key);\n const el: HTMLInputElement = e.target as HTMLInputElement;\n this._inputValue.set(el.value);\n this._setMask();\n\n const isTextarea = el.tagName.toLowerCase() === 'textarea';\n\n if (el.type !== 'number') {\n if (this._insertNumpadDecimalMarker(e, el)) {\n return;\n }\n if (e.key === MaskExpression.ARROW_UP && !isTextarea) {\n e.preventDefault();\n }\n if (\n e.key === MaskExpression.ARROW_LEFT ||\n e.key === MaskExpression.BACKSPACE ||\n e.key === MaskExpression.DELETE\n ) {\n if (e.key === MaskExpression.BACKSPACE && el.value.length === 0) {\n el.selectionStart = el.selectionEnd;\n }\n if (e.key === MaskExpression.BACKSPACE && (el.selectionStart as number) !== 0) {\n const prefixLength = this._maskService.prefix.length;\n // Use the service value: it holds the config defaults when the input is not\n // bound and the bound value otherwise, so an explicitly bound empty array is\n // respected instead of silently falling back to the defaults (#1512).\n const specialCharacters = this._maskService.specialCharacters;\n\n if (prefixLength > 1 && (el.selectionStart as number) <= prefixLength) {\n el.setSelectionRange(prefixLength, el.selectionEnd);\n } else {\n if (\n this._inputValue().length !== (el.selectionStart as number) &&\n (el.selectionStart as number) !== 1\n ) {\n const collapsedCaret = el.selectionStart === el.selectionEnd;\n const hopFrom = el.selectionStart;\n while (\n specialCharacters.includes(\n (\n this._inputValue()[(el.selectionStart as number) - 1] ??\n MaskExpression.EMPTY_STRING\n ).toString()\n ) &&\n ((prefixLength >= 1 &&\n (el.selectionStart as number) > prefixLength) ||\n prefixLength === 0)\n ) {\n el.setSelectionRange(\n (el.selectionStart as number) - 1,\n el.selectionEnd\n );\n }\n // keepCharacterPositions: take the digit in front of the separators\n // along, so the default delete blanks it instead of only moving the caret\n if (\n this._maskService.keepCharacterPositions &&\n collapsedCaret &&\n el.selectionStart !== hopFrom &&\n (el.selectionStart as number) > prefixLength &&\n // a caret inside the suffix hops over its leading space only\n (hopFrom as number) <=\n suffixStart(this._inputValue(), this._maskService.suffix)\n ) {\n el.setSelectionRange(\n (el.selectionStart as number) - 1,\n el.selectionEnd\n );\n }\n }\n }\n }\n const { prefix, suffix, maskExpression, specialCharacters } = this._maskService;\n // Number masks keep their own caret handling around a prefix or suffix.\n const numberMask =\n maskExpression.startsWith(MaskExpression.SEPARATOR) ||\n maskExpression.startsWith(MaskExpression.PERCENT);\n // The clamp below pulls a caret inside the prefix up to its end, so remember the\n // one sitting exactly in front of the first digit: Delete may act there. Only for\n // a mask that starts with a digit slot after a prefix of two or more characters:\n // a caret at 1 is the first-character case of onInput, which shifts it by the\n // prefix length and so lands the edit one slot off.\n const deleteAtFirstSlot =\n e.key === MaskExpression.DELETE &&\n el.selectionStart === el.selectionEnd &&\n el.selectionStart === prefix.length &&\n prefix.length > 1 &&\n el.value.startsWith(prefix) &&\n !numberMask &&\n // a date field cannot lose its first digit without scrambling the others\n !isDateTimeMask(maskExpression) &&\n !specialCharacters.includes(maskExpression.charAt(0));\n this.checkSelectionOnDeletion(el);\n if (\n prefix.length &&\n !deleteAtFirstSlot &&\n (el.selectionStart as number) <= prefix.length &&\n (el.selectionEnd as number) <= prefix.length\n ) {\n e.preventDefault();\n }\n // Nothing editable follows the caret at the end of the digits, and the clamp\n // above put it right in front of the suffix: Delete would eat its first char.\n // Skipped when the display carries no suffix (hiddenInput) and for number masks.\n if (\n e.key === MaskExpression.DELETE &&\n suffix &&\n !numberMask &&\n el.selectionStart === el.selectionEnd &&\n (el.selectionStart as number) >=\n suffixStart(this._inputValue(), this._maskService.suffix)\n ) {\n e.preventDefault();\n }\n const cursorStart: number | null = el.selectionStart;\n if (\n e.key === MaskExpression.BACKSPACE &&\n !el.readOnly &&\n cursorStart === 0 &&\n el.selectionEnd === el.value.length &&\n el.value.length !== 0\n ) {\n // Handle the clear fully here instead of emitting the model change and\n // relying on the browser's default deletion + input event to update the\n // view: Firefox can drop the default action after the emission below\n // triggers change detection (DOM churn around the input), leaving the\n // model empty but the view untouched until a second Backspace (#1350).\n e.preventDefault();\n // The default action (and its input event) is suppressed, so the\n // inputTransformFn would never see the cleared value; run it here (#1651).\n const transformedEmpty = this._maskService.inputTransformFn\n ? this._maskService.inputTransformFn(MaskExpression.EMPTY_STRING)\n : MaskExpression.EMPTY_STRING;\n const clearedValue =\n typeof transformedEmpty === 'string' || typeof transformedEmpty === 'number'\n ? String(transformedEmpty)\n : MaskExpression.EMPTY_STRING;\n const displayValue = this._maskService.applyMask(\n clearedValue,\n this._maskService.maskExpression,\n 0,\n false,\n true\n );\n el.value = displayValue;\n this._inputValue.set(displayValue);\n const caret = Math.min(this._maskService.prefix.length, displayValue.length);\n el.setSelectionRange(caret, caret);\n }\n }\n if (\n !!this._maskService.suffix &&\n this._maskService.suffix.length > 1 &&\n this._inputValue().length - this._maskService.suffix.length <\n (el.selectionStart as number)\n ) {\n el.setSelectionRange(\n this._inputValue().length - this._maskService.suffix.length,\n this._inputValue().length\n );\n } else if (\n (e.code === 'KeyA' && e.ctrlKey) ||\n (e.code === 'KeyA' && e.metaKey) // Cmd + A (Mac)\n ) {\n el.setSelectionRange(0, this._getActualInputLength());\n e.preventDefault();\n }\n this._maskService.selStart = el.selectionStart;\n this._maskService.selEnd = el.selectionEnd;\n }\n }\n\n /**\n * #1641: on layouts whose decimal separator is a comma, the numeric keypad still emits\n * a period, which a separator mask configured with a comma decimal marker rejects. The\n * keypad decimal key (`key: 'Decimal'`, or a `.` from `code: 'NumpadDecimal'`) is\n * therefore turned into the configured marker. Only the keypad key is intercepted: a\n * period typed on the main keyboard keeps its normal behavior (e.g. as a thousand\n * separator). Returns true when the key press was handled.\n */\n private _insertNumpadDecimalMarker(e: KeyboardEvent, el: HTMLInputElement): boolean {\n const isNumpadDecimal =\n e.key === MaskExpression.NUMPAD_DECIMAL ||\n (e.code === MaskExpression.NUMPAD_DECIMAL_CODE && e.key === MaskExpression.DOT);\n if (\n !isNumpadDecimal ||\n e.ctrlKey ||\n e.metaKey ||\n e.altKey ||\n el.readOnly ||\n !this._maskValue().startsWith(MaskExpression.SEPARATOR)\n ) {\n return false;\n }\n const configuredMarker = this._maskService.decimalMarker;\n const marker = Array.isArray(configuredMarker)\n ? configuredMarker.find((item) => item !== this._maskService.thousandSeparator)\n : configuredMarker;\n if (marker !== MaskExpression.COMMA) {\n return false;\n }\n const start = el.selectionStart ?? el.value.length;\n const end = el.selectionEnd ?? start;\n e.preventDefault();\n this._code.set(MaskExpression.NUMPAD_DECIMAL_CODE);\n this._inputValue.set(el.value);\n this._maskService.selStart = start;\n this._maskService.selEnd = end;\n el.value = `${el.value.slice(0, start)}${marker}${el.value.slice(end)}`;\n el.setSelectionRange(start + 1, start + 1);\n el.dispatchEvent(\n new InputEvent('input', { inputType: 'insertText', data: marker, bubbles: true })\n );\n return true;\n }\n\n /**\n * Runs `write` as a programmatic write: the model updates it causes do not dirty the control\n * (see `_programmaticWrite`). Nested writes keep the flag of the enclosing one.\n */\n private _writeProgrammatically<T>(write: () => T): T {\n const enclosingWrite = this._programmaticWrite;\n this._programmaticWrite = true;\n try {\n return write();\n } finally {\n this._programmaticWrite = enclosingWrite;\n }\n }\n\n /**\n * Passes a model value the mask derived from a programmatic write on to the control, without\n * dirtying it.\n *\n * When the directive is the bound control's own accessor, `fn` is Angular's `updateControl`\n * callback: the value goes the way its view-change pipeline takes it (`setValue` without a\n * view echo, then `viewToModelUpdate`, which emits `ngModelChange`), minus `markAsDirty()`,\n * so the control and its ancestors keep the dirty and touched state they had. In every other\n * case (a wrapper forwarding the accessor, which transforms the value or reacts to it\n * itself; Signal Forms; no control) `fn` is the contract the caller registered and is called;\n * the nearest control then gets back the pristine and untouched state it had before the call.\n */\n private _emitProgrammaticValue(fn: (value: unknown) => void, value: unknown): void {\n const ngControl = this._resolveNgControl();\n const control = ngControl?.control;\n if (\n ngControl?.valueAccessor === this &&\n control &&\n typeof control.setValue === 'function'\n ) {\n control.setValue(value, { emitModelToViewChange: false });\n ngControl.viewToModelUpdate(value);\n return;\n }\n const wasPristine = ngControl ? Boolean(ngControl.pristine) : true;\n const wasUntouched = ngControl ? Boolean(ngControl.untouched) : true;\n fn(value);\n if (wasPristine && ngControl?.dirty && typeof control?.markAsPristine === 'function') {\n control.markAsPristine({ onlySelf: true });\n }\n if (wasUntouched && ngControl?.touched && typeof control?.markAsUntouched === 'function') {\n control.markAsUntouched({ onlySelf: true });\n }\n }\n\n /** It writes the value in the input */\n public writeValue(controlValue: unknown): void {\n if (!this._configApplied && this.mask()) {\n // Called before the first ngOnChanges pass configured the mask service (happens with\n // Signal Forms' [formField], whose control-sync instruction runs before sibling\n // directives' ngOnChanges). Defer and replay once the configuration is applied.\n this._pendingInitialValue = controlValue;\n this._hasPendingInitialValue = true;\n return;\n }\n // Skip the model echo of a value we just propagated ourselves (see the\n // _lastPropagatedValue doc). Empty writes are never skipped: form reset('') must\n // always clear the display and the currentValue/previousValue service state below.\n const lastPropagated = this._lastPropagatedValue;\n this._lastPropagatedValue = null;\n if (\n lastPropagated !== null &&\n lastPropagated !== '' &&\n (typeof controlValue === 'string' || typeof controlValue === 'number') &&\n String(controlValue) === lastPropagated\n ) {\n return;\n }\n const writeSequence = ++this._writeSequence;\n let value = controlValue;\n const inputTransformFn = this._maskService.inputTransformFn;\n if (typeof value === 'object' && value !== null && 'value' in value) {\n if ('disable' in value) {\n this.setDisabledState(Boolean(value.disable));\n }\n\n value = value.value;\n }\n if (value !== null) {\n value = inputTransformFn ? inputTransformFn(value) : value;\n }\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n value === null ||\n typeof value === 'undefined'\n ) {\n if (value === null || typeof value === 'undefined' || value === '') {\n this._maskService.currentValue = '';\n this._maskService.previousValue = '';\n }\n\n let inputValue: string | number | null | undefined = value;\n if (\n typeof inputValue === 'number' ||\n this._maskValue().startsWith(MaskExpression.SEPARATOR)\n ) {\n inputValue = displayToPlainDecimal(\n String(inputValue),\n this._maskService.decimalMarker,\n this._maskService.thousandSeparator\n );\n const localeDecimalMarker = this._maskService.currentLocaleDecimalMarker();\n if (!Array.isArray(this._maskService.decimalMarker)) {\n inputValue =\n this._maskService.decimalMarker !== localeDecimalMarker\n ? inputValue.replace(\n localeDecimalMarker,\n this._maskService.decimalMarker\n )\n : inputValue;\n }\n\n // Read before the precision pass rewrites the decimals with a dot.\n const commaDecimal = usesCommaDecimal(\n inputValue,\n this._maskService.decimalMarker,\n this._maskService.thousandSeparator\n );\n if (\n this._maskService.leadZero &&\n inputValue &&\n this.mask() &&\n this._maskService.dropSpecialCharacters !== false\n ) {\n inputValue = this._maskService._checkPrecision(\n this._maskService.maskExpression,\n inputValue as string\n );\n }\n\n if (commaDecimal) {\n inputValue = inputValue\n .toString()\n .replace(MaskExpression.DOT, MaskExpression.COMMA);\n }\n if (\n this._resolvedMaskInput().startsWith(MaskExpression.SEPARATOR) &&\n this._maskService.leadZero\n ) {\n const isFirstWrite = !this._maskService.isInitialized;\n afterNextRender(\n () => {\n if (writeSequence !== this._writeSequence) {\n // A later write or a user edit superseded this one: this stale\n // value must not be re-applied over it (#1691).\n return;\n }\n this._ngZone.run(() => {\n // On initial load, temporarily set isInitialized to false\n // so formControlResult returns early and doesn't mark form as dirty.\n // On later writeValue-driven writes, leave isInitialized as-is: this pass\n // may legitimately need to push a leadZero-normalized value (e.g.\n // '10.2' -> '10.20') back to the FormControl, as a programmatic write that\n // does not dirty it — see the `should change formValue` unit tests, which\n // assert the normalized value lands in `form.value` after a programmatic\n // setValue.\n if (isFirstWrite) {\n this._maskService.isInitialized = false;\n }\n this._writeProgrammatically(() =>\n this._maskService.applyMask(\n inputValue?.toString() ?? '',\n this._maskService.maskExpression\n )\n );\n if (isFirstWrite) {\n this._maskService.isInitialized = true;\n }\n // Zoneless CD does not auto-flush after a deferred callback; request\n // a check so form.pristine/form.value bindings reflect the new state.\n this._changeDetectorRef.markForCheck();\n });\n },\n { injector: this._injector }\n );\n }\n this._maskService.isNumberValue = true;\n } else if (typeof inputValue === 'string' && inputValue !== '') {\n // A concrete string write on a non-separator mask ends the numeric emission a\n // previous numeric write switched on. Empty writes (reset, null, '') carry no\n // type information and keep the current state.\n this._maskService.isNumberValue = false;\n }\n\n if (typeof inputValue !== 'string' || value === null || typeof value === 'undefined') {\n inputValue = '';\n }\n\n this._inputValue.set(inputValue);\n this._setMask();\n\n if (\n (inputValue && this._maskService.maskExpression) ||\n (this._maskService.maskExpression &&\n (this._maskService.prefix || this._maskService.showMaskTyped))\n ) {\n // Let the service we know we are writing value so that triggering onChange function won't happen during applyMask\n this._maskService.writingValue = true;\n\n // The raw control value: a boxed `{value, disable}` write never equals the plain value\n // the mask emits, so its echo still replaces the box in the control.\n this._writtenValue = { value: controlValue };\n let displayValue: string;\n try {\n displayValue = this._writeProgrammatically(() =>\n this._maskedOrVerbatim(inputValue)\n );\n } finally {\n this._writtenValue = null;\n }\n // A nested write (setValue inside a valueChanges subscriber) already rendered its own,\n // newer value: do not overwrite it with this stale one.\n if (writeSequence === this._writeSequence) {\n this._maskService.formElementProperty = ['value', displayValue];\n this._writeElementValueSync(displayValue);\n }\n // Let the service know we've finished writing value\n this._maskService.writingValue = false;\n this._maskService.isInitialized = true;\n } else {\n this._maskService.formElementProperty = ['value', inputValue];\n this._writeElementValueSync(inputValue);\n this._maskService.isInitialized = true;\n }\n // Programmatic writes (setValue/patchValue called outside a signal/effect context)\n // don't schedule CD under zoneless change detection. Request a check so bindings\n // reading form.pristine/form.dirty/form.value on the host template stay in sync.\n this._changeDetectorRef.markForCheck();\n } else {\n // eslint-disable-next-line no-console\n console.warn(\n 'Ngx-mask writeValue work with string | number, your current value:',\n typeof value\n );\n }\n }\n\n /**\n * Mirrors a writeValue-driven render into the DOM synchronously, in the same\n * change-detection pass (#1305). The service's `formElementProperty` setter defers all\n * writes via queueMicrotask (to keep FIFO ordering with config-driven re-renders and\n * dodge ExpressionChanged issues), but consumers that read `nativeElement.value` DURING\n * the CD pass — Angular Material's floating label (`MatInput.empty`), CDK autofill —\n * never see a value that only lands in a later microtask. The deferred write still runs\n * afterwards and re-applies the same final value, so ordering guarantees are preserved.\n *\n * Skipped while a mask reconfiguration is pending (`mask()` input changed but\n * `ngOnChanges` has not applied it yet — e.g. `mask.set(...)` + `setValue(...)` before\n * the next CD pass): the value just computed used the STALE mask config, and rendering\n * it synchronously would expose an intermediate state that the deferred pipeline is\n * about to supersede. Multi-masks (`||`) resolve `_maskValue` to one alternative and\n * therefore also fall back to the deferred-only path.\n */\n private _writeElementValueSync(value: string): void {\n if (this._resolvedMaskInput() !== this._maskValue()) {\n return;\n }\n this._renderer.setProperty(this._elementRef.nativeElement, 'value', value);\n }\n\n /** The `mask` input with a user-defined alias (config maskAliases) expanded, if any. */\n private _resolvedMaskInput(): string {\n return resolveMaskAlias(this.mask(), this._config.maskAliases);\n }\n\n public registerOnChange(fn: typeof this.onChange): void {\n // Angular only calls this in classic ControlValueAccessor mode (reactive/template forms).\n // Its invocation is therefore our reliable signal that we are NOT in Signal Forms mode.\n this._isCvaMode.set(true);\n const originalFn = fn;\n this._maskService.onChange = this.onChange = (value: unknown) => {\n if (!this._writtenValue || !Object.is(this._writtenValue.value, value)) {\n if (this._programmaticWrite) {\n this._emitProgrammaticValue(originalFn, value);\n } else {\n // Angular's callback marks the control dirty: it receives the user edits.\n originalFn(value);\n }\n }\n this._propagateToValueModel(value);\n };\n }\n\n public registerOnValidatorChange(fn: () => void): void {\n this._onValidatorChange = fn;\n }\n\n public registerOnTouched(fn: typeof this.onTouch): void {\n this.onTouch = () => {\n fn();\n if (!this.touched()) {\n this.touched.set(true);\n }\n };\n }\n\n /**\n * Pushes the current unmasked value into the `value` model input. In Signal Forms mode this\n * fires the `valueChange` output that Angular listens to; in CVA mode it is a harmless write\n * to a model nobody reads. We flag `_skipNextValueEffect` so the resulting model change does\n * not bounce back through the value effect and overwrite the raw `_inputValue`.\n */\n private _propagateToValueModel(value: unknown): void {\n const stringValue = value === null || typeof value === 'undefined' ? '' : String(value);\n this._lastPropagatedValue = stringValue;\n this._valuePropagatedByEdit = stringValue;\n untracked(() => {\n if (String(this.value()) !== stringValue) {\n this._skipNextValueEffect.set(true);\n this.value.set(stringValue);\n }\n });\n }\n\n /**\n * Whether the `value`-model effect will render `value` itself via writeValue(): only in\n * standalone `[(value)]` / Signal Forms mode (Angular's writeValue owns rendering in CVA mode), not for\n * the model echo of our own onChange propagation (`_skipNextValueEffect`), and only when it\n * differs from what is already rendered. Shared with ngOnChanges (#1671), which must leave\n * exactly that render to the effect.\n */\n private _valueEffectWillWrite(value: unknown): boolean {\n return (\n !this._isCvaMode() &&\n !this._skipNextValueEffect() &&\n String(value) !== String(this._inputValue())\n );\n }\n\n /**\n * Focus the input element.\n * Required by FormValueControl interface for Signal Forms.\n */\n public focus(): void {\n this._maskService._elementRef?.nativeElement?.focus();\n }\n\n public checkSelectionOnDeletion(el: HTMLInputElement): void {\n const prefixLength = this._maskService.prefix.length;\n const suffixLength = this._maskService.suffix.length;\n const inputValueLength = this._inputValue().length;\n\n el.selectionStart = Math.min(\n Math.max(prefixLength, el.selectionStart as number),\n inputValueLength - suffixLength\n );\n el.selectionEnd = Math.min(\n Math.max(prefixLength, el.selectionEnd as number),\n inputValueLength - suffixLength\n );\n }\n\n /**\n * It disables the input element.\n *\n * Mirrors `_writeElementValueSync` (#1305): the service's `formElementProperty` setter\n * defers ALL DOM writes via `queueMicrotask` to dodge ExpressionChangedAfterItHasBeenChecked\n * and keep FIFO ordering with config-driven re-renders. For `disabled` specifically, that\n * deferral leaves `nativeElement.disabled` stale for at least one microtask after Angular\n * Forms' `setUpControl` calls this method synchronously during init — long enough for a\n * consumer reading the DOM property in the same synchronous phase (or another deferred write\n * racing in FIFO order) to observe the wrong value, e.g. an initially-disabled FormControl\n * whose native input briefly (or, depending on interleaving, persistently) reports\n * `disabled === false` (#1633). Writing synchronously here closes that gap; the deferred\n * write below still runs afterwards and re-applies the same final value, preserving the\n * existing ordering guarantees other call sites rely on.\n */\n public setDisabledState(isDisabled: boolean): void {\n this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);\n this._maskService.formElementProperty = ['disabled', isDisabled];\n }\n\n private _mirrorInput<K extends MirroredInput>(key: K, value: NgxMaskService[K]): void {\n this._maskService[key] = value;\n }\n\n private _applyMask(renderInputValue: boolean): void {\n this._maskService.maskExpression = this._maskService._repeatPatternSymbols(\n this._maskValue() || ''\n );\n if (!renderInputValue) {\n // Consume the one-shot flags ngOnChanges set for THIS render, as applyMask would:\n // writingValue (thousandSeparator change) and maskChanged (mask change). Nothing\n // else clears them when the following writeValue() takes its no-applyMask branch.\n this._maskService.writingValue = false;\n this._maskService._clearMaskChangedUnlessTriggered();\n return;\n }\n this._maskService.formElementProperty = [\n 'value',\n this._maskedOrVerbatim(this._inputValue()),\n ];\n // The skeleton render of an empty value returns before the service consumes them, and a\n // one-shot flag left set swallows the first edit that follows.\n this._maskService.writingValue = false;\n this._maskService._clearMaskChangedUnlessTriggered();\n }\n\n /**\n * Renders `inputValue` through the mask, falling back to the raw value verbatim when the\n * mask cannot process ANY of it (#1615, e.g. a sentinel like 'ONGOING' written into a\n * digits-only control). Values that PARTIALLY match keep regular masking.\n *\n * Shared by writeValue() and _applyMask() (called from every ngOnChanges pass, including\n * ones triggered by an UNRELATED input like `disabled`) so the verbatim verdict for a\n * value written once via writeValue() is not lost on a later re-render that replays the\n * same raw `inputValue` outside of writeValue — which would otherwise re-run regular\n * masking, produce an empty result, and emit it through onChange, clobbering the model.\n *\n * Excludes an actual mask RECONFIGURATION (`maskChanged`): when the mask itself just\n * changed, a value that no longer matches must clear through the regular path (see\n * trigger-on-mask-change.spec.ts) — verbatim passthrough only covers re-renders of the\n * SAME mask.\n */\n private _maskedOrVerbatim(inputValue: string): string {\n // Snapshot before applyMask(): it resets maskChanged internally as part of emitting\n // (or skipping) the change, so it must be read before the call, not after.\n const wasMaskChanged = this._maskService.maskChanged;\n const maskedResult = this._maskService.applyMask(\n inputValue,\n this._maskService.maskExpression\n );\n return !maskedResult &&\n inputValue &&\n !wasMaskChanged &&\n this._maskService.removeMask(inputValue)\n ? inputValue\n : maskedResult;\n }\n\n private _validateTime(value: string): ValidationErrors | null {\n const rowMaskLen: number = this._maskValue()\n .split(MaskExpression.EMPTY_STRING)\n .filter((s: string) => s !== ':').length;\n if (!value) {\n return null; // Don't validate empty values to allow for optional form control\n }\n\n if (\n (+(value[value.length - 1] ?? -1) === 0 && value.length < rowMaskLen) ||\n value.length <= rowMaskLen - 2\n ) {\n return this._createValidationError(value);\n }\n\n return null;\n }\n\n private _getActualInputLength() {\n return (\n this._maskService.actualValue.length ||\n this._maskService.actualValue.length + this._maskService.prefix.length\n );\n }\n\n /**\n * For `||` multi-masks only (#1583): a value shorter than the currently selected\n * alternative is still valid when it is a pattern-valid prefix of that alternative\n * ending exactly at a special-character boundary (e.g. `0` for `0,N`) and it meets\n * the length requirement of at least one alternative (e.g. `1`). Values stopping\n * mid-pattern-block (e.g. `112A` for `000SS`) remain invalid.\n */\n private _isCompleteAlternativeBoundary(processedValue: string): boolean {\n const alternatives = this._maskExpressionArray();\n if (!alternatives.length) {\n return false;\n }\n const maskValue = this._maskValue();\n const cleanValue = this._maskService.removeMask(processedValue);\n const cleanMask = this._maskService.removeMask(maskValue);\n const isPatternPrefix = cleanValue\n .split(MaskExpression.EMPTY_STRING)\n .every((character, index) =>\n this._maskService._checkSymbolMask(character, cleanMask.charAt(index))\n );\n if (!isPatternPrefix) {\n return false;\n }\n let patternCount = 0;\n let boundaryCharacter: string = MaskExpression.EMPTY_STRING;\n for (const maskCharacter of maskValue) {\n if (patternCount === cleanValue.length) {\n boundaryCharacter = maskCharacter;\n break;\n }\n if (!this._maskService.specialCharacters.includes(maskCharacter)) {\n patternCount++;\n }\n }\n if (\n !boundaryCharacter ||\n !this._maskService.specialCharacters.includes(boundaryCharacter)\n ) {\n return false;\n }\n return alternatives.some((alternative) => {\n const requiredLength = this._maskService.dropSpecialCharacters\n ? alternative.length - this._maskService.checkDropSpecialCharAmount(alternative)\n : this._maskService.prefix\n ? alternative.length + this._maskService.prefix.length\n : alternative.length;\n // Exact match, not `>=`: a longer value must not pass on the strength of a\n // shorter alternative it has already outgrown (#1645, 7 digits vs `00000 9`).\n return processedValue.length === requiredLength;\n });\n }\n\n /**\n * True when every character of the mask expression is either a pattern token or a\n * special character — i.e. the mask has no quantifiers (`*`, `?`), curly-bracket\n * repetitions or other constructs the position-aware matcher does not model.\n */\n private _isPlainTokenMask(mask: string): boolean {\n return mask\n .split(MaskExpression.EMPTY_STRING)\n .every(\n (symbol: string) =>\n !!this._maskService.patterns[symbol] ||\n this._maskService.specialCharacters.includes(symbol)\n );\n }\n\n /**\n * Backtracking match of a value against a mask mixing optional and mandatory pattern\n * tokens (#1515, e.g. `999SSS`). Optional tokens may be left unfilled; special\n * characters may be absent from the value (dropSpecialCharacters). The value is valid\n * when it is fully consumed and every remaining mask token is optional or special.\n */\n private _matchesMaskWithOptionalSkip(value: string, mask: string): boolean {\n const patterns = this._maskService.patterns;\n // Optional tokens branch twice (consume or skip), so the same (maskIndex, valueIndex)\n // state is reached through many paths: remember the ones that already failed.\n const failed = new Set<number>();\n const match = (maskIndex: number, valueIndex: number): boolean => {\n const state = maskIndex * (value.length + 1) + valueIndex;\n if (failed.has(state)) {\n return false;\n }\n const matched = matchFrom(maskIndex, valueIndex);\n if (!matched) {\n failed.add(state);\n }\n return matched;\n };\n const matchFrom = (maskIndex: number, valueIndex: number): boolean => {\n if (valueIndex === value.length) {\n return mask\n .slice(maskIndex)\n .split(MaskExpression.EMPTY_STRING)\n .every((symbol: string) => !patterns[symbol] || !!patterns[symbol]?.optional);\n }\n if (maskIndex === mask.length) {\n return false;\n }\n const maskSymbol = mask[maskIndex] as string;\n const valueSymbol = value[valueIndex] as string;\n const pattern = patterns[maskSymbol];\n if (pattern) {\n if (\n this._maskService._checkSymbolMask(valueSymbol, maskSymbol) &&\n match(maskIndex + 1, valueIndex + 1)\n ) {\n return true;\n }\n return !!pattern.optional && match(maskIndex + 1, valueIndex);\n }\n // Special character: consume it when present in the value, otherwise treat it\n // as dropped (dropSpecialCharacters).\n if (valueSymbol === maskSymbol && match(maskIndex + 1, valueIndex + 1)) {\n return true;\n }\n return match(maskIndex + 1, valueIndex);\n };\n return match(0, 0);\n }\n\n private _createValidationError(actualValue: string): ValidationErrors {\n return {\n mask: {\n requiredMask: this._maskValue(),\n actualValue,\n },\n };\n }\n\n private _setMask() {\n this._maskExpressionArray().some((mask): boolean | void => {\n const specialChart: boolean = mask\n .split(MaskExpression.EMPTY_STRING)\n .some((char) => this._maskService.specialCharacters.includes(char));\n if (\n (specialChart &&\n this._inputValue() &&\n this._areAllCharactersInEachStringSame(this._maskExpressionArray())) ||\n mask.includes(MaskExpression.CURLY_BRACKETS_LEFT)\n ) {\n const test =\n this._maskService.removeMask(this._inputValue())?.length <=\n this._maskService.removeMask(mask)?.length;\n if (test) {\n const maskValue = mask.includes(MaskExpression.CURLY_BRACKETS_LEFT)\n ? this._maskService._repeatPatternSymbols(mask)\n : mask;\n this._maskValue.set(maskValue);\n this._maskService.maskExpression = maskValue;\n return test;\n } else {\n const expression =\n this._maskExpressionArray()[this._maskExpressionArray().length - 1] ??\n MaskExpression.EMPTY_STRING;\n\n const maskValue = expression.includes(MaskExpression.CURLY_BRACKETS_LEFT)\n ? this._maskService._repeatPatternSymbols(expression)\n : expression;\n this._maskValue.set(maskValue);\n this._maskService.maskExpression = maskValue;\n }\n } else {\n const cleanMask = this._maskService.removeMask(mask);\n const check: boolean = this._maskService\n .removeMask(this._inputValue())\n ?.split(MaskExpression.EMPTY_STRING)\n .every((character, index) => {\n const indexMask = cleanMask.charAt(index);\n return this._maskService._checkSymbolMask(character, indexMask);\n });\n\n if (check || this._justPasted()) {\n this._maskValue.set(mask);\n this._maskService.maskExpression = mask;\n return check;\n }\n }\n });\n }\n\n private _areAllCharactersInEachStringSame(array: string[]): boolean {\n const specialCharacters = this._maskService.specialCharacters;\n\n function removeSpecialCharacters(str: string): string {\n const regex = new RegExp(\n `[${specialCharacters.map((ch) => escapeRegExp(ch)).join('')}]`,\n 'g'\n );\n return str.replace(regex, '');\n }\n\n const processedArr = array.map(removeSpecialCharacters);\n\n return processedArr.every((str) => {\n const uniqueCharacters = new Set(str);\n return uniqueCharacters.size === 1;\n });\n }\n}\n","import type { PipeTransform } from '@angular/core';\nimport { EnvironmentInjector, inject, Injector, Pipe } from '@angular/core';\n\nimport type { NgxMaskConfig } from './ngx-mask.config';\nimport { NGX_MASK_CONFIG, resolveMaskAlias } from './ngx-mask.config';\nimport { NgxMaskService } from './ngx-mask.service';\nimport { MaskExpression } from './ngx-mask-expression.enum';\n\n@Pipe({\n name: 'mask',\n pure: true,\n})\nexport class NgxMaskPipe implements PipeTransform {\n private readonly defaultOptions = inject<NgxMaskConfig>(NGX_MASK_CONFIG);\n\n private readonly _environmentInjector = inject(EnvironmentInjector);\n\n private _maskService!: NgxMaskService;\n\n private _maskExpressionArray: string[] = [];\n\n private mask = '';\n\n public transform(\n value: string | number,\n mask: string,\n { patterns, maskAliases, ...config }: Partial<NgxMaskConfig> = {} as Partial<NgxMaskConfig>\n ): string {\n let processedValue: string | number = value;\n\n // NgxMaskService is stateful (built for the directive, which keeps value history across\n // keystrokes), so each transform gets a fresh instance: nothing from a previous call can\n // leak into this one (#1669).\n this._maskService = Injector.create({\n providers: [\n NgxMaskService,\n { provide: NGX_MASK_CONFIG, useValue: this.defaultOptions },\n ],\n parent: this._environmentInjector,\n }).get(NgxMaskService);\n\n // User-defined aliases expand BEFORE any other mask processing (incl. `||` handling).\n const resolvedMask = resolveMaskAlias(mask, {\n ...this.defaultOptions.maskAliases,\n ...maskAliases,\n });\n\n const currentConfig = {\n maskExpression: resolvedMask,\n ...this.defaultOptions,\n ...config,\n patterns: {\n ...this.defaultOptions.patterns,\n ...patterns,\n },\n };\n\n Object.entries(currentConfig).forEach(([key, val]) => {\n (this._maskService as unknown as Record<string, unknown>)[key] = val;\n });\n\n if (resolvedMask.includes('||')) {\n this._maskExpressionArray = resolvedMask\n .split('||')\n .sort((a: string, b: string) => a.length - b.length);\n this._setMask(`${processedValue}`);\n return this._maskService.applyMask(`${processedValue}`, this.mask);\n }\n\n if (resolvedMask.includes(MaskExpression.CURLY_BRACKETS_LEFT)) {\n return this._maskService.applyMask(\n `${processedValue}`,\n this._maskService._repeatPatternSymbols(resolvedMask)\n );\n }\n\n if (resolvedMask.startsWith(MaskExpression.SEPARATOR)) {\n if (config.decimalMarker) {\n this._maskService.decimalMarker = config.decimalMarker;\n }\n if (config.thousandSeparator) {\n this._maskService.thousandSeparator = config.thousandSeparator;\n }\n if (config.leadZero) {\n this._maskService.leadZero = config.leadZero;\n }\n\n processedValue = String(processedValue);\n const localeDecimalMarker = this._maskService.currentLocaleDecimalMarker();\n\n if (!Array.isArray(this._maskService.decimalMarker)) {\n processedValue =\n this._maskService.decimalMarker !== localeDecimalMarker\n ? (processedValue as string).replace(\n localeDecimalMarker,\n this._maskService.decimalMarker\n )\n : processedValue;\n }\n\n if (\n this._maskService.leadZero &&\n processedValue &&\n this._maskService.dropSpecialCharacters !== false\n ) {\n processedValue = this._maskService._checkPrecision(\n resolvedMask,\n processedValue as string\n );\n }\n\n if (this._maskService.decimalMarker === MaskExpression.COMMA) {\n processedValue = (processedValue as string).replace(\n MaskExpression.DOT,\n MaskExpression.COMMA\n );\n }\n }\n\n if (processedValue === null || typeof processedValue === 'undefined') {\n return this._maskService.applyMask('', resolvedMask);\n }\n\n return this._maskService.applyMask(`${processedValue}`, resolvedMask);\n }\n\n private _setMask(value: string) {\n if (this._maskExpressionArray.length > 0) {\n this._maskExpressionArray.some((mask): boolean | void => {\n const test =\n this._maskService.removeMask(value)?.length <=\n this._maskService.removeMask(mask)?.length;\n if (value && test) {\n this.mask = mask;\n return test;\n } else {\n this.mask =\n this._maskExpressionArray[this._maskExpressionArray.length - 1] ??\n MaskExpression.EMPTY_STRING;\n }\n });\n }\n }\n}\n"],"mappings":"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"}