UNPKG

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
{"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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"}