UNPKG

ngxsmk-tel-input

Version:

Angular international telephone input (intl-tel-input UI + libphonenumber-js validation). ControlValueAccessor. SSR-safe.

3,331 lines 179 kB
import * as i0 from '@angular/core';
import { signal, computed, Injectable, input, output, EventEmitter, inject, PLATFORM_ID, ElementRef, effect, forwardRef, Output, Input, ViewChild, Optional, ChangeDetectionStrategy, Component, InjectionToken, NgModule, Inject } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
import { parsePhoneNumberFromString, getNumberType, AsYouType, validatePhoneNumberLength } from 'libphonenumber-js';
import { BehaviorSubject, from } from 'rxjs';
import * as i1 from '@angular/common/http';
import { HttpHeaders } from '@angular/common/http';
import { map, catchError } from 'rxjs/operators';

/**
 * Signal-based API utilities for ngxsmk-tel-input.
 * Provides reactive signal-based interfaces for modern Angular applications.
 */
/**
 * Creates a default phone input state signal.
 */
function createPhoneInputState() {
    return signal({
        raw: '',
        e164: null,
        iso2: 'US',
        isValid: false,
        touched: false,
        errors: null
    });
}
/**
 * Computed signal for formatted phone number display.
 */
function createFormattedValueSignal(state, nationalDisplay) {
    return computed(() => {
        const current = state();
        if (!current.raw)
            return '';
        if (nationalDisplay() === 'formatted' && current.e164) {
            // Return formatted national format
            return current.raw;
        }
        return current.raw;
    });
}
/**
 * Computed signal for validation status.
 */
function createValidationStatusSignal(state) {
    return computed(() => {
        const current = state();
        const errors = current.errors || {};
        const errorKeys = Object.keys(errors);
        return {
            isValid: current.isValid,
            isInvalid: !current.isValid && current.touched,
            hasErrors: errorKeys.length > 0,
            errorKeys
        };
    });
}
/**
 * Computed signal for phone number metadata.
 */
function createPhoneMetadataSignal(state) {
    return computed(() => {
        const current = state();
        if (!current.e164) {
            return {
                countryCode: current.iso2,
                dialCode: null,
                nationalNumber: null,
                internationalFormat: null
            };
        }
        // Extract dial code from E.164
        const dialCodeMatch = current.e164.match(/^\+\d{1,3}/);
        const dialCode = dialCodeMatch ? dialCodeMatch[0].slice(1) : null;
        return {
            countryCode: current.iso2,
            dialCode,
            nationalNumber: current.raw,
            internationalFormat: current.e164
        };
    });
}

/**
 * Phone intelligence service for advanced features
 * Provides carrier detection, number type detection, and smart formatting
 */
class PhoneIntelligenceService {
    /**
     * Detect carrier and number type
     */
    detectCarrierAndType(phoneNumber, country) {
        try {
            const parsed = parsePhoneNumberFromString(phoneNumber, country);
            if (!parsed || !parsed.isValid()) {
                return null;
            }
            // getNumberType can accept PhoneNumber object directly (it's compatible with ParsedNumber)
            // Use type assertion to work around TypeScript type mismatch
            const numberType = getNumberType(parsed) || 'UNKNOWN';
            return {
                country: parsed.country,
                type: numberType,
                isMobile: numberType === 'MOBILE' || numberType === 'FIXED_LINE_OR_MOBILE',
                isLandline: numberType === 'FIXED_LINE' || numberType === 'FIXED_LINE_OR_MOBILE',
                isTollFree: numberType === 'TOLL_FREE',
                isPremiumRate: numberType === 'PREMIUM_RATE',
                isVoip: numberType === 'VOIP'
            };
        }
        catch {
            return null;
        }
    }
    /**
     * Get number type description
     */
    getNumberTypeDescription(type) {
        const descriptions = {
            'MOBILE': 'Mobile phone',
            'FIXED_LINE': 'Landline',
            'FIXED_LINE_OR_MOBILE': 'Mobile or landline',
            'TOLL_FREE': 'Toll-free number',
            'PREMIUM_RATE': 'Premium rate number',
            'VOIP': 'VoIP number',
            'UNKNOWN': 'Unknown type'
        };
        return descriptions[type] || 'Unknown';
    }
    /**
     * Suggest format corrections
     */
    suggestFormatCorrection(input, country) {
        if (!input || input.length < 3) {
            return null;
        }
        const digits = input.replace(/\D/g, '');
        if (digits.length < 3) {
            return null;
        }
        try {
            // Try to parse as-is
            let parsed = parsePhoneNumberFromString(input, country);
            if (parsed && parsed.isValid()) {
                return null; // Already valid
            }
            // Common corrections
            const suggestions = [];
            // Remove leading zeros
            if (digits.startsWith('0') && digits.length > 1) {
                const withoutZero = digits.substring(1);
                const testParsed = parsePhoneNumberFromString(withoutZero, country);
                if (testParsed && testParsed.isValid()) {
                    suggestions.push({
                        original: input,
                        suggested: testParsed.formatNational(),
                        confidence: 0.8,
                        reason: 'Removed leading zero'
                    });
                }
            }
            // Add country code if missing
            if (!input.startsWith('+') && !input.startsWith('00')) {
                const withPlus = `+${digits}`;
                const testParsed = parsePhoneNumberFromString(withPlus);
                if (testParsed && testParsed.isValid()) {
                    suggestions.push({
                        original: input,
                        suggested: testParsed.formatNational(),
                        confidence: 0.7,
                        reason: 'Added country code'
                    });
                }
            }
            // Fix common formatting issues
            const formatted = this.fixCommonFormattingIssues(input, country);
            if (formatted && formatted !== input) {
                const testParsed = parsePhoneNumberFromString(formatted, country);
                if (testParsed && testParsed.isValid()) {
                    suggestions.push({
                        original: input,
                        suggested: testParsed.formatNational(),
                        confidence: 0.6,
                        reason: 'Fixed formatting'
                    });
                }
            }
            // Return highest confidence suggestion
            if (suggestions.length > 0) {
                return suggestions.sort((a, b) => b.confidence - a.confidence)[0];
            }
            return null;
        }
        catch {
            return null;
        }
    }
    /**
     * Fix common formatting issues
     */
    fixCommonFormattingIssues(input, country) {
        let fixed = input;
        // Remove spaces and dashes, keep only digits and +
        fixed = fixed.replace(/[^\d+]/g, '');
        // Remove multiple plus signs
        if (fixed.indexOf('+') !== fixed.lastIndexOf('+')) {
            fixed = '+' + fixed.replace(/\+/g, '');
        }
        // Remove leading zeros after country code
        if (fixed.startsWith('+')) {
            const parts = fixed.split('+');
            if (parts.length > 1) {
                const numberPart = parts[1].replace(/^0+/, '');
                fixed = '+' + numberPart;
            }
        }
        return fixed;
    }
    /**
     * Get timezone for phone number
     */
    getTimezone(phoneNumber, country) {
        try {
            const parsed = parsePhoneNumberFromString(phoneNumber, country);
            if (!parsed) {
                return null;
            }
            // Basic timezone mapping (simplified)
            const timezoneMap = {
                'US': 'America/New_York',
                'GB': 'Europe/London',
                'AU': 'Australia/Sydney',
                'CA': 'America/Toronto',
                'DE': 'Europe/Berlin',
                'FR': 'Europe/Paris',
                'JP': 'Asia/Tokyo',
                'CN': 'Asia/Shanghai',
                'IN': 'Asia/Kolkata',
                'BR': 'America/Sao_Paulo',
                'MX': 'America/Mexico_City',
                'RU': 'Europe/Moscow'
            };
            return timezoneMap[parsed.country || country] || null;
        }
        catch {
            return null;
        }
    }
    /**
     * Check if number is likely spam (basic heuristic)
     */
    isLikelySpam(phoneNumber, country) {
        try {
            const parsed = parsePhoneNumberFromString(phoneNumber, country);
            if (!parsed) {
                return false;
            }
            const nationalNumber = parsed.nationalNumber;
            // Check for suspicious patterns
            const suspiciousPatterns = [
                /^(\d)\1{6,}$/, // Same digit repeated 7+ times
                /^123456789/, // Sequential
                /^987654321/, // Reverse sequential
                /^0000000/, // All zeros
            ];
            return suspiciousPatterns.some(pattern => pattern.test(nationalNumber));
        }
        catch {
            return false;
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PhoneIntelligenceService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PhoneIntelligenceService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PhoneIntelligenceService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }] });

/**
 * Service for parsing and validating phone numbers using libphonenumber-js.
 * Provides caching for improved performance and enhanced validation features.
 *
 * @example
 * ```typescript
 * constructor(private telService: NgxsmkTelInputService) {}
 *
 * validatePhone(input: string, country: CountryCode) {
 *   const result = this.telService.parse(input, country);
 *   return result.isValid;
 * }
 * ```
 */
class NgxsmkTelInputService {
    constructor() {
        this.parseCache = new Map();
        this.parseWithInvalidCache = new Map();
        this.validationCache = new Map();
        this.CACHE_SIZE_LIMIT = 1000;
    }
    /**
     * Parses a phone number string and returns formatted results.
     * Results are cached for performance.
     *
     * @param input - The phone number string to parse (can include formatting)
     * @param iso2 - ISO 3166-1 alpha-2 country code (e.g., 'US', 'GB')
     * @returns ParseResult with E.164 format, national format, and validity status
     *
     * @example
     * ```typescript
     * const result = service.parse('202-555-1234', 'US');
     * // result.e164 = '+12025551234'
     * // result.national = '(202) 555-1234'
     * // result.isValid = true
     * ```
     */
    parse(input, iso2) {
        const cacheKey = `${input || ''}|${iso2}`;
        if (this.parseCache.has(cacheKey)) {
            return this.parseCache.get(cacheKey);
        }
        try {
            const phone = parsePhoneNumberFromString(input || '', iso2);
            if (!phone) {
                const result = { e164: null, national: null, isValid: false };
                this.setCacheValue(this.parseCache, cacheKey, result);
                return result;
            }
            const isValid = phone.isValid();
            const result = {
                e164: isValid ? phone.number : null,
                national: phone.formatNational(),
                isValid
            };
            this.setCacheValue(this.parseCache, cacheKey, result);
            return result;
        }
        catch {
            const result = { e164: null, national: null, isValid: false };
            this.setCacheValue(this.parseCache, cacheKey, result);
            return result;
        }
    }
    /**
     * Validates whether a phone number string is valid for the given country.
     * Results are cached for performance.
     *
     * @param input - The phone number string to validate
     * @param iso2 - ISO 3166-1 alpha-2 country code
     * @returns true if the phone number is valid, false otherwise
     *
     * @example
     * ```typescript
     * const isValid = service.isValid('202-555-1234', 'US'); // true
     * const isInvalid = service.isValid('123', 'US'); // false
     * ```
     */
    isValid(input, iso2) {
        const cacheKey = `${input || ''}|${iso2}`;
        if (this.validationCache.has(cacheKey)) {
            return this.validationCache.get(cacheKey);
        }
        try {
            const phone = parsePhoneNumberFromString(input || '', iso2);
            const result = !!phone && phone.isValid();
            this.setCacheValue(this.validationCache, cacheKey, result);
            return result;
        }
        catch {
            this.setCacheValue(this.validationCache, cacheKey, false);
            return false;
        }
    }
    /**
     * Sets a value in the cache, implementing LRU eviction when cache is full.
     * @param cache - The cache Map to update
     * @param key - The cache key
     * @param value - The value to cache
     */
    setCacheValue(cache, key, value) {
        if (cache.size >= this.CACHE_SIZE_LIMIT) {
            const firstKey = cache.keys().next().value;
            if (firstKey)
                cache.delete(firstKey);
        }
        cache.set(key, value);
    }
    /**
     * Clears all caches. Useful for memory management or testing.
     */
    clearCache() {
        this.parseCache.clear();
        this.parseWithInvalidCache.clear();
        this.validationCache.clear();
    }
    /**
     * Checks if the input appears to be an international number with an invalid country code.
     * This helps detect cases like "1123456789" where "11" is not a valid country code.
     *
     * @param input - The phone number string to check
     * @returns true if the input appears to be an invalid international number
     * @private
     */
    isInvalidInternationalNumber(input) {
        if (!input || input.length < 3)
            return false;
        const digits = input.replace(/\D/g, '');
        if (digits.length < 3)
            return false;
        for (let i = 1; i <= 3 && i <= digits.length; i++) {
            const potentialCountryCode = digits.substring(0, i);
            const remainingDigits = digits.substring(i);
            if (remainingDigits.length >= 3) {
                try {
                    const internationalNumber = `+${potentialCountryCode}${remainingDigits}`;
                    const phone = parsePhoneNumberFromString(internationalNumber);
                    if (!phone) {
                        if (input.startsWith('+') || (potentialCountryCode.length >= 1 && potentialCountryCode.length <= 3)) {
                            return true;
                        }
                    }
                }
                catch {
                    return true;
                }
            }
        }
        return false;
    }
    /**
     * Enhanced parse method that detects invalid international numbers.
     * This is useful for providing better error messages to users.
     * Results are cached for performance.
     *
     * @param input - The phone number string to parse
     * @param iso2 - ISO 3166-1 alpha-2 country code
     * @returns ParseWithInvalidResult with additional invalid country code detection
     *
     * @example
     * ```typescript
     * const result = service.parseWithInvalidDetection('1123456789', 'US');
     * // result.isInvalidInternational = true (because "11" is not a valid country code)
     * // result.isValid = false
     * ```
     */
    parseWithInvalidDetection(input, iso2) {
        const cacheKey = `${input || ''}|${iso2}`;
        if (this.parseWithInvalidCache.has(cacheKey)) {
            return this.parseWithInvalidCache.get(cacheKey);
        }
        try {
            const phone = parsePhoneNumberFromString(input || '', iso2);
            const isInvalidInternational = this.isInvalidInternationalNumber(input);
            if (!phone) {
                const result = {
                    e164: null,
                    national: null,
                    isValid: false,
                    isInvalidInternational
                };
                this.setCacheValue(this.parseWithInvalidCache, cacheKey, result);
                return result;
            }
            const isValid = phone.isValid();
            const result = {
                e164: isValid ? phone.number : null,
                national: phone.formatNational(),
                isValid,
                isInvalidInternational
            };
            this.setCacheValue(this.parseWithInvalidCache, cacheKey, result);
            return result;
        }
        catch {
            const isInvalidInternational = this.isInvalidInternationalNumber(input);
            const result = {
                e164: null,
                national: null,
                isValid: false,
                isInvalidInternational
            };
            this.setCacheValue(this.parseWithInvalidCache, cacheKey, result);
            return result;
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgxsmkTelInputService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgxsmkTelInputService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgxsmkTelInputService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }] });

/**
 * Angular telephone input component with country dropdown, flags, and robust validation/formatting.
 * Wraps intl-tel-input for the UI and libphonenumber-js for parsing/validation.
 * Implements ControlValueAccessor for seamless integration with Angular Forms.
 *
 * **Compatibility**: Works with Angular 17+ and supports both:
 * - Zone.js (traditional Angular change detection)
 * - Zoneless Angular (Angular 18+ without Zone.js)
 * - All data binding types (property, event, two-way)
 * - Reactive Forms and Template-driven Forms
 * - Signals (Angular 16+)
 *
 * **Mobile Responsive**: Fully optimized for mobile devices with:
 * - Touch-friendly tap targets (44x44px minimum)
 * - Prevents iOS zoom (16px font size)
 * - Responsive dropdown that adapts to viewport
 * - Safe area insets support for notched devices
 * - Optimized touch interactions
 *
 * @example
 * ```html
 * <ngxsmk-tel-input
 *   formControlName="phone"
 *   label="Phone Number"
 *   [initialCountry]="'US'"
 *   [preferredCountries]="['US','GB']">
 * </ngxsmk-tel-input>
 * ```
 */
class NgxsmkTelInputComponent {
    set telI18n(v) { this.i18n = v; }
    set telLocalizedCountries(v) { this.localizedCountries = v; }
    constructor(zone, tel, cdr) {
        this.zone = zone;
        this.tel = tel;
        this.cdr = cdr;
        // ========== Signal-based API (Angular 17+) ==========
        /** Signal-based input: Initial country to select. Use 'auto' for geo-location detection. */
        this.initialCountrySignal = input('US');
        /** Signal-based input: Countries to show at the top of the dropdown list. */
        this.preferredCountriesSignal = input(['US', 'GB']);
        /** Signal-based input: Restrict selectable countries to this list. */
        this.onlyCountriesSignal = input(undefined);
        /** Signal-based input: When true, shows dial code outside the input field. */
        this.separateDialCodeSignal = input(true);
        /** Signal-based input: Enable or disable the country dropdown. */
        this.allowDropdownSignal = input(true);
        /** Signal-based input: Display format - 'formatted' => national with spaces; 'digits' => digits only */
        this.nationalDisplaySignal = input('formatted');
        /** Signal-based input: Format timing - 'typing' (live), 'blur', or 'off' */
        this.formatWhenValidSignal = input('typing');
        /** Signal-based input: Size variant */
        this.sizeSignal = input('md');
        /** Signal-based input: Style variant */
        this.variantSignal = input('outline');
        /** Signal-based input: Theme preference */
        this.themeSignal = input('auto');
        /** Signal-based input: Disabled state */
        this.disabledSignal = input(false);
        /** Signal-based output: Emitted when country selection changes */
        this.countryChangeSignal = output();
        /** Signal-based output: Emitted when validity changes */
        this.validityChangeSignal = output();
        /** Signal-based output: Emitted on every input change */
        this.inputChangeSignal = output();
        /** Internal state signal for reactive state management */
        this.stateSignal = createPhoneInputState();
        /** Computed signal: Current phone input state */
        this.state = this.stateSignal.asReadonly();
        /** Computed signal: Formatted display value */
        this.formattedValue = createFormattedValueSignal(this.stateSignal, this.nationalDisplaySignal);
        /** Computed signal: Validation status */
        this.validationStatus = createValidationStatusSignal(this.stateSignal);
        /** Computed signal: Phone number metadata */
        this.phoneMetadata = createPhoneMetadataSignal(this.stateSignal);
        /** Computed signal: Whether the input is valid */
        this.isValid = computed(() => this.stateSignal().isValid);
        /** Computed signal: Whether the input has errors */
        this.hasErrors = computed(() => {
            const errors = this.stateSignal().errors;
            return errors !== null && Object.keys(errors).length > 0;
        });
        /** Computed signal: Whether to show error message */
        this.showError = computed(() => {
            if (this.isDestroyed)
                return false;
            const state = this.stateSignal();
            const hasErrors = state.errors !== null && Object.keys(state.errors).length > 0;
            return this.showErrorWhenTouched ? (state.touched && hasErrors) : hasErrors;
        });
        /** Computed signal: Current E.164 value */
        this.e164Value = computed(() => this.stateSignal().e164);
        /** Computed signal: Current raw input value */
        this.rawValue = computed(() => this.stateSignal().raw);
        /** Computed signal: Current country ISO2 code */
        this.currentCountry = computed(() => this.stateSignal().iso2);
        // ========== Traditional @Input/@Output API (backward compatibility) ==========
        /** Initial country to select. Use 'auto' for geo-location detection (defaults to 'US'). */
        this.initialCountry = 'US';
        /** Countries to show at the top of the dropdown list. */
        this.preferredCountries = ['US', 'GB'];
        /** When true, shows dial code outside the input field (after the flag). */
        this.separateDialCode = true;
        /** Enable or disable the country dropdown. */
        this.allowDropdown = true;
        /** 'formatted' => national with spaces; 'digits' => digits only */
        this.nationalDisplay = 'formatted';
        /** 'typing' (live), 'blur', or 'off' */
        this.formatWhenValid = 'typing';
        this.autocomplete = 'tel';
        this.disabled = false;
        this.size = 'md';
        this.variant = 'outline';
        this.showClear = true;
        this.autoFocus = false;
        this.selectOnFocus = false;
        this.showErrorWhenTouched = true;
        this.dropdownAttachToBody = true;
        this.dropdownZIndex = 2000;
        this.clearAriaLabel = 'Clear phone number';
        this.dir = 'ltr';
        this.autoPlaceholder = 'off';
        this.digitsOnly = true;
        this.lockWhenValid = true;
        this.theme = 'auto';
        /** Enable carrier and number type detection */
        this.enableIntelligence = false;
        /** Enable format suggestions */
        this.enableFormatSuggestions = false;
        this.countryChange = new EventEmitter();
        this.validityChange = new EventEmitter();
        this.inputChange = new EventEmitter();
        this.intelligenceChange = new EventEmitter();
        this.formatSuggestion = new EventEmitter();
        this.iti = null;
        this.onChange = () => { };
        this.onTouchedCb = () => { };
        this.lastEmittedValid = false;
        this.pendingWrite = null;
        this.touched = false;
        this.isDestroyed = false;
        this.eventListeners = [];
        this.searchInputCleanupFunctions = [];
        this.allowDropdownWasTrue = false;
        this.suppressEvents = false;
        this.themeObserver = null;
        this.globalThemeObserver = null;
        this.resolvedId = this.inputId || ('tel-' + Math.random().toString(36).slice(2));
        this.platformId = inject(PLATFORM_ID);
        this.currentTheme = 'light';
        this.lastThemeConfig = null;
        this.isRequired = false;
        this.intelligence = inject(PhoneIntelligenceService, { optional: true });
        this.hostElementRef = inject(ElementRef);
        // Watch for theme signal changes
        effect(() => {
            if (!isPlatformBrowser(this.platformId) || this.isDestroyed)
                return;
            // Check both signal and traditional input
            const theme = this.themeSignal() || this.theme;
            if (theme !== undefined && theme !== this.lastThemeConfig) {
                this.lastThemeConfig = theme;
                // Apply theme immediately (works even before plugin is initialized)
                this.detectAndApplyTheme();
            }
        });
    }
    /**
     * Helper method to run code inside Angular zone if available, otherwise just run it.
     * Works with both Zone.js and zoneless Angular.
     */
    runInZone(fn) {
        if (this.zone) {
            this.zone.run(fn);
        }
        else {
            fn();
            this.cdr.markForCheck();
        }
    }
    /**
     * Helper method to run code outside Angular zone if available, otherwise just run it.
     * Works with both Zone.js and zoneless Angular.
     */
    runOutsideZone(fn) {
        if (this.zone) {
            this.zone.runOutsideAngular(fn);
        }
        else {
            fn();
        }
    }
    /**
     * Helper method for requestAnimationFrame with fallback for older browsers.
     */
    requestAnimationFrame(fn) {
        if (typeof window !== 'undefined') {
            const raf = window.requestAnimationFrame ||
                window.webkitRequestAnimationFrame ||
                window.mozRequestAnimationFrame ||
                window.msRequestAnimationFrame ||
                ((callback) => setTimeout(callback, 16));
            raf(fn);
        }
        else {
            fn();
        }
    }
    /**
     * Determines if dropdown should be attached to body.
     * On mobile screens (<=768px), returns false to show dropdown inline instead of as modal.
     */
    shouldAttachToBody() {
        if (!this.dropdownAttachToBody)
            return false;
        if (typeof window === 'undefined')
            return false;
        // On mobile, don't attach to body to avoid modal popup behavior
        // Use fallback for older browsers
        const width = window.innerWidth || window.clientWidth || 1024;
        return width > 768;
    }
    /**
     * Angular lifecycle hook called after the view is initialized.
     * Initializes the intl-tel-input plugin and sets up event listeners.
     */
    ngAfterViewInit() {
        if (!isPlatformBrowser(this.platformId) || this.isDestroyed)
            return;
        // Ensure theme is applied on initial render
        // Use setTimeout to ensure host element is fully available
        setTimeout(() => {
            if (!this.isDestroyed) {
                this.detectAndApplyTheme();
            }
        }, 0);
        this.setupDropdownThemeObserver();
        this.setupGlobalThemeObserver();
        void this.initAndWire();
    }
    async initAndWire() {
        if (this.isDestroyed)
            return;
        await this.initIntlTelInput();
        if (this.isDestroyed)
            return;
        this.bindDomListeners();
        if (this.pendingWrite !== null && !this.isDestroyed) {
            const v = this.pendingWrite;
            this.pendingWrite = null;
            this.writeValue(v);
        }
        if (this.autoFocus && !this.isDestroyed) {
            this.requestAnimationFrame(() => {
                if (!this.isDestroyed)
                    this.focus();
            });
        }
    }
    ngOnChanges(changes) {
        if (!isPlatformBrowser(this.platformId) || this.isDestroyed)
            return;
        // Check for signal changes or traditional input changes
        const configChanged = [
            'initialCountry', 'preferredCountries', 'onlyCountries',
            'separateDialCode', 'allowDropdown',
            'i18n', 'localizedCountries', 'dir',
            'autoPlaceholder', 'utilsScript', 'customPlaceholder'
        ].some(k => k in changes && !changes[k]?.firstChange);
        // Also check if any signal inputs have changed (signals trigger change detection automatically)
        if (configChanged && this.iti && !this.isDestroyed) {
            this.reinitPlugin();
            this.validatorChange?.();
        }
        // Handle theme changes from traditional @Input
        if ('theme' in changes && !changes['theme'].firstChange) {
            const theme = this.theme;
            if (theme !== this.lastThemeConfig) {
                this.lastThemeConfig = theme;
                this.detectAndApplyTheme();
                // Mark for check to ensure view updates with OnPush
                this.cdr.markForCheck();
            }
        }
    }
    ngOnDestroy() {
        this.isDestroyed = true;
        this.destroyPlugin();
        this.cleanupEventListeners();
        this.cleanupSearchInputListeners();
        if (this.themeObserver) {
            this.themeObserver.disconnect();
            this.themeObserver = null;
        }
        if (this.globalThemeObserver) {
            this.globalThemeObserver.disconnect();
            this.globalThemeObserver = null;
        }
    }
    /**
     * Writes a new value to the form control.
     * Called by Angular Forms when the control value changes programmatically.
     * @param val - The new value (E.164 format string or null)
     */
    writeValue(val) {
        if (!this.inputRef || this.isDestroyed)
            return;
        if (!this.iti) {
            this.pendingWrite = val ?? '';
            return;
        }
        // Get current state for comparison (will be checked after setNumber with correct country)
        const currentE164 = this.stateSignal().e164;
        this.suppressEvents = true;
        try {
            // Call setNumber() FIRST to let intl-tel-input detect and set the correct country
            // This is critical when the incoming value has a different country code
            this.iti.setNumber(val || '');
            // Now get the country code AFTER setNumber has potentially changed it
            const iso2 = this.currentIso2();
            // Parse with the correct country code
            const parsed = this.tel.parseWithInvalidDetection(val ?? '', iso2);
            const incomingE164 = parsed.e164;
            // Avoid unnecessary updates if E.164 value hasn't changed
            if (currentE164 === incomingE164) {
                // Even if E.164 is the same, update if the display value would be different
                // (e.g., user changed format settings or country changed)
                const currentRaw = this.stateSignal().raw;
                const currentIso2 = this.stateSignal().iso2;
                // If country changed, we need to update
                if (currentIso2 !== iso2) {
                    // Country changed, proceed with update
                }
                else {
                    // Same country, check if display value is different
                    const nsn = incomingE164
                        ? this.nsnFromE164(incomingE164, iso2)
                        : this.stripLeadingZero(this.toNSN(parsed.national ?? (val ?? '')));
                    const display = this.displayValue(nsn, iso2);
                    if (currentRaw === display) {
                        return; // Nothing to update
                    }
                }
            }
            const nsn = incomingE164
                ? this.nsnFromE164(incomingE164, iso2)
                : this.stripLeadingZero(this.toNSN(parsed.national ?? (val ?? '')));
            const display = this.displayValue(nsn, iso2);
            this.setInputValue(display);
            // Update state signal without triggering Angular Forms onChange
            // (writeValue is called BY Angular Forms, so we shouldn't notify it back)
            this.stateSignal.update(state => ({
                ...state,
                raw: display,
                e164: incomingE164,
                iso2,
                isValid: parsed.isValid && !parsed.isInvalidInternational,
                errors: (parsed.isValid && !parsed.isInvalidInternational) ? null : (parsed.isInvalidInternational ? { phoneInvalidCountryCode: true, phoneInvalid: false } : { phoneInvalid: true, phoneInvalidCountryCode: false })
            }));
            // Emit inputChange for external listeners (but NOT onChange to avoid loop)
            this.runInZone(() => {
                this.inputChange.emit({ raw: display, e164: incomingE164, iso2 });
                this.inputChangeSignal.emit({ raw: display, e164: incomingE164, iso2 });
            });
            // Mark for check to ensure view updates (works in both zone and zoneless)
            this.cdr.markForCheck();
        }
        finally {
            this.suppressEvents = false;
        }
    }
    /**
     * Registers a callback function that is called when the control's value changes.
     * @param fn - Callback function that receives the new value (string | null)
     */
    registerOnChange(fn) { this.onChange = fn; }
    /**
     * Registers a callback function that is called when the control is touched.
     * @param fn - Callback function to be called on touch
     */
    registerOnTouched(fn) { this.onTouchedCb = fn; }
    /**
     * Sets the disabled state of the control.
     * Called by Angular Forms when the control's disabled state changes.
     * @param isDisabled - Whether the control should be disabled
     */
    setDisabledState(isDisabled) {
        if (this.isDestroyed)
            return;
        this.disabled = isDisabled;
        if (this.inputRef)
            this.inputRef.nativeElement.disabled = isDisabled;
        if (this.iti) {
            if (isDisabled && this.allowDropdown) {
                this.allowDropdownWasTrue = true;
                this.allowDropdown = false;
                this.reinitPlugin(); // closes popup & removes handlers
            }
            else if (!isDisabled && this.allowDropdownWasTrue) {
                this.allowDropdown = true;
                this.allowDropdownWasTrue = false;
                this.reinitPlugin();
            }
            else {
                this.applyDisabledUi(isDisabled);
            }
        }
        else {
            this.applyDisabledUi(isDisabled);
        }
    }
    /**
     * Validates the phone number input.
     * Returns validation errors if the number is invalid, null if valid.
     * @param _ - The form control (unused, but required by Validator interface)
     * @returns ValidationErrors object with error keys, or null if valid
     */
    validate(control) {
        if (this.isDestroyed)
            return null;
        // Update isRequired based on control validators
        // Check if control has required validator by testing with null value
        try {
            if (control.validator) {
                const testControl = { value: null };
                const errors = control.validator(testControl);
                this.isRequired = !!(errors && errors['required']);
            }
            else {
                this.isRequired = false;
            }
        }
        catch (e) {
            // Fallback to not required if validator check fails
            this.isRequired = false;
        }
        const raw = this.currentRaw();
        if (!raw)
            return null;
        const parsed = this.tel.parseWithInvalidDetection(raw, this.currentIso2());
        const valid = parsed.isValid && !parsed.isInvalidInternational;
        if (valid !== this.lastEmittedValid) {
            this.lastEmittedValid = valid;
            // Update state signal
            this.stateSignal.update(state => ({
                ...state,
                isValid: valid,
                errors: valid ? null : (parsed.isInvalidInternational ? { phoneInvalidCountryCode: true, phoneInvalid: false } : { phoneInvalid: true, phoneInvalidCountryCode: false })
            }));
            // Emit both traditional and signal-based outputs
            this.validityChange.emit(valid);
            this.validityChangeSignal.emit(valid);
            // Mark for check when validity changes
            this.cdr.markForCheck();
        }
        if (!valid) {
            if (parsed.isInvalidInternational) {
                return { phoneInvalidCountryCode: true };
            }
            return { phoneInvalid: true };
        }
        return null;
    }
    /**
     * Registers a callback function that is called when validator inputs change.
     * @param fn - Callback function to be called when validation should be re-run
     */
    registerOnValidatorChange(fn) { this.validatorChange = fn; }
    /**
     * Programmatically focuses the input field.
     * If selectOnFocus is enabled, also selects all text.
     */
    focus() {
        if (this.isDestroyed || !this.inputRef)
            return;
        this.inputRef.nativeElement.focus();
        if (this.selectOnFocus) {
            const el = this.inputRef.nativeElement;
            this.requestAnimationFrame(() => {
                if (!this.isDestroyed) {
                    try {
                        el.setSelectionRange(0, el.value.length);
                    }
                    catch (e) {
                        // Fallback for browsers that don't support setSelectionRange
                        if (el.select) {
                            el.select();
                        }
                    }
                }
            });
        }
    }
    /**
     * Programmatically selects a country.
     * @param iso2 - ISO 3166-1 alpha-2 country code (e.g., 'US', 'GB')
     */
    selectCountry(iso2) {
        if (this.iti && !this.isDestroyed) {
            this.iti.setCountry(iso2.toLowerCase());
            this.handleInput();
        }
    }
    /**
     * Clears the input field and refocuses it.
     */
    clearInput() {
        if (this.isDestroyed)
            return;
        this.setInputValue('');
        this.handleInput();
        this.inputRef.nativeElement.focus();
    }
    async initIntlTelInput() {
        if (this.isDestroyed)
            return;
        const [{ default: intlTelInput }] = await Promise.all([import('intl-tel-input')]);
        const toLowerKeys = (m) => {
            if (!m)
                return undefined;
            const out = {};
            for (const k in m)
                if (Object.prototype.hasOwnProperty.call(m, k)) {
                    const v = m[k];
                    if (v != null)
                        out[k.toLowerCase()] = v;
                }
            return out;
        };
        // Use signal values if available, fallback to traditional inputs
        const initialCountry = this.initialCountrySignal() || this.initialCountry;
        const preferredCountries = this.preferredCountriesSignal() || this.preferredCountries;
        const onlyCountries = this.onlyCountriesSignal() ?? this.onlyCountries;
        const allowDropdown = this.allowDropdownSignal() ?? this.allowDropdown;
        const separateDialCode = this.separateDialCodeSignal() ?? this.separateDialCode;
        const config = {
            initialCountry: initialCountry === 'auto' ? 'auto' : (initialCountry?.toLowerCase() || 'us'),
            preferredCountries: (preferredCountries ?? []).map(c => c.toLowerCase()),
            onlyCountries: (onlyCountries ?? []).map(c => c.toLowerCase()),
            nationalMode: true,
            allowDropdown,
            separateDialCode,
            geoIpLookup: (cb) => cb('us'),
            autoPlaceholder: this.autoPlaceholder,
            utilsScript: this.utilsScript,
            customPlaceholder: this.customPlaceholder,
            i18n: this.i18n,
            localizedCountries: toLowerKeys(this.localizedCountries),
            // On mobile, don't attach to body to avoid modal behavior
            dropdownContainer: this.shouldAttachToBody() ? (typeof document !== 'undefined' ? document.body : undefined) : undefined
        };
        this.runOutsideZone(() => {
            if (!this.isDestroyed) {
                this.iti = intlTelInput(this.inputRef.nativeElement, config);
            }
        });
        if (!this.isDestroyed) {
            this.inputRef.nativeElement.style.setProperty('--tel-dd-z', String(this.dropdownZIndex));
            this.applyDisabledUi(this.disabled);
        }
    }
    async reinitPlugin() {
        if (this.isDestroyed)
            return;
        const prevIso2 = (this.iti?.getSelectedCountryData?.().iso2 || this.initialCountry || 'US').toString().toLowerCase();
        const prevValue = this.currentRaw();
        this.destroyPlugin();
        await this.initIntlTelInput();
        this.bindDomListeners();
        if (!this.isDestroyed) {
            try {
                this.iti?.setCountry(prevIso2);
            }
            catch (e) {
                // Ignore errors when setting country (e.g., invalid country code)
            }
            if (prevValue) {
                this.setInputValue(prevValue);
                this.handleInput();
            }
            this.applyDisabledUi(this.disabled);
        }
    }
    destroyPlugin() {
        if (this.iti) {
            this.iti.destroy();
            this.iti = null;
        }
    }
    // ---------- Input listeners ----------
    bindDomListeners() {
        if (this.isDestroyed || !this.inputRef)
            return;
        const el = this.inputRef.nativeElement;
        this.runOutsideZone(() => {
            const beforeInputHandler = (ev) => {
                if (this.isDestroyed || !this.digitsOnly)
                    return;
                const inputEvent = ev;
                const data = inputEvent.data;
                if (this.lockWhenValid && this.isCurrentlyValid()) {
                    const selStart = el.selectionStart ?? 0;
                    const selEnd = el.selectionEnd ?? 0;
                    const selCollapsed = selStart === selEnd;
                    const isDigit = !!data && inputEvent.inputType === 'insertText' && data >= '0' && data <= '9';
                    if (selCollapsed && isDigit) {
                        ev.preventDefault();
                        return;
                    }
                }
                if (!data || inputEvent.inputType !== 'insertText')
                    return;
                const isDigit = data >= '0' && data <= '9';
                if (!isDigit) {
                    ev.preventDefault();
                    return;
                }
                const start = el.selectionStart ?? el.value.length;
                const end = el.selectionEnd ?? el.value.length;
                const prospective = el.value.slice(0, start) + data + el.value.slice(end);
                const nsn = this.stripLeadingZero(this.toNSN(prospective));
                const iso2 = this.currentIso2();
                if (this.wouldExceedMax(nsn, iso2)) {
                    ev.preventDefault();
                    return;
                }
            };
            const pasteHandler = (e) => {
                if (this.isDestroyed)
                    return;
                const clipboardEvent = e;
                // Support both standard ClipboardEvent and IE11 fallback
                const clipboardData = clipboardEvent.clipboardData ||
                    (window.clipboardData) ||
                    null;
                let text = '';
                if (clipboardData) {
                    try {
                        text = clipboardData.getData('text') || '';
                    }
                    catch (err) {
                        // Fallback for browsers without clipboardData support
                        text = '';
                    }
                }
                e.preventDefault();
                const iso2 = this.currentIso2();
                let digits = this.stripLeadingZero(this.toNSN(text));
                while (this.wouldExceedMax(digits, iso2)) {
                    digits = digits.slice(0, -1);
                    if (!digits)
                        break;
                }
                const start = el.selectionStart ?? el.value.length;
                const end = el.selectionEnd ?? el.value.length;
                // Use setRangeText with fallback for older browsers
                if (el.setRangeText) {
                    try {
                        el.setRangeText(digits, start, end, 'end');
                    }
                    catch (e) {
                        // Fallback for browsers without setRangeText support
                        el.value = el.value.substring(0, start) + digits + el.value.substring(end);
                    }
                }
                else {
                    el.value = el.value.substring(0, start) + digits + el.value.substring(end);
                }
                this.requestAnimationFrame(() => {
                    if (!this.isDestroyed)
                        this.handleInput();
                });
            };
            const inputHandler = () => {
                if (!this.isDestroyed)
                    this.handleInput();
            };
            const countryChangeHandler = () => {
                if (this.isDestroyed || this.suppressEvents)
                    return;
                const iso2 = this.currentIso2();
                // Update state signal
                this.stateSignal.update(state => ({
                    ...state,
                    iso2
                }));
                this.runInZone(() => {
                    const changeEvent = { iso2 };
                    // Emit both traditional and signal-based outputs
                    this.countryChange.emit(changeEvent);
                    this.countryChangeSignal.emit(changeEvent);
                    this.validatorChange?.();
                });
                this.handleInput();
            };
            const blurHandler = () => {
                if (!this.isDestroyed)
                    this.onBlur();
            };
            // Store listeners for cleanup
            this.eventListeners = [
                { element: el, event: 'beforeinput', handler: beforeInputHandler },
                { element: el, event: 'paste', handler: pasteHandler },
                { element: el, event: 'input', handler: inputHandler },
                { element: el, event: 'countrychange', handler: countryChangeHandler },
                { element: el, event: 'blur', handler: blurHandler }
            ];
            this.eventListeners.forEach(({ element, event, handler }) => {
                element.addEventListener(event, handler);
            });
        });
    }
    onBlur() {
        if (this.isDestroyed)
            return;
        this.touched = true;
        // Update state signal
        this.stateSignal.update(state => ({
            ...state,
            touched: true
        }));
        this.runInZone(() => {
            this.onTouchedCb();
            // Trigger validation on blur
            this.validatorChange?.();
        });
        // Mark for check to update view with OnPush (works in both zone and zoneless)
        this.cdr.markForCheck();
        const formatWhenValidBlur = this.formatWhenValidSignal() || this.formatWhenValid;
        if (formatWhenValidBlur === 'off')
            return;
        const iso2 = this.currentIso2();
        const digits = this.stripLeadingZero(this.toNSN(this.currentRaw()));
        const parsed = this.tel.parseWithInvalidDetection(digits, iso2);
        if (!parsed.e164 && !parsed.isValid)
            return;
        const nsn = parsed.e164 ? this.nsnFromE164(parsed.e164, iso2) : digits;
        if (formatWhenValidBlur !== 'typing') {
            this.setInputValue(this.displayValue(nsn, iso2));
        }
    }
    onFocus() {
        if (this.isDestroyed || !this.selectOnFocus || !this.inputRef)
            return;
        const el = this.inputRef.nativeElement;
        this.requestAnimationFrame(() => {
            if (!this.isDestroyed) {
                try {
                    if (el.setSelectionRange) {
                        el.setSelectionRange(0, el.value.length);
                    }
                    else if (el.select) {
                        // Fallback for browsers that don't support setSelectionRange
                        el.select();
                    }
                }
                catch (e) {
                    // Ignore errors in older browsers
                }
            }
        });
    }
    handleInput() {
        if (this.suppressEvents || this.isDestroyed)
            return;
        // Cache currentRaw() to avoid multiple DOM reads
        const rawValue = this.currentRaw();
        const iso2 = this.currentIso2();
        const digits = this.stripLeadingZero(this.toNSN(rawValue));
        const parsed = this.tel.parseWithInvalidDetection(digits, iso2);
        const isValid = parsed.isValid && !parsed.isInvalidInternational;
        // Batch state signal update
        this.stateSignal.update(state => ({
            ...state,
            raw: rawValue,
            e164: parsed.e164,
            iso2,
            isValid,
            errors: isValid ? null : (parsed.isInvalidInternational ? { phoneInvalidCountryCode: true, phoneInvalid: false } : { phoneInvalid: true, phoneInvalidCountryCode: false })
        }));
        // Intelligence features
        if (this.enableIntelligence && this.intelligence && parsed.e164) {
            const carrierInfo = this.intelligence.detectCarrierAndType(parsed.e164, iso2);
            if (carrierInfo) {
                this.intelligenceChange.emit(carrierInfo);
            }
        }
        // Format suggestions
        if (this.enableFormatSuggestions && this.intelligence && !parsed.isValid) {
            const suggestion = this.intelligence.suggestFormatCorrection(rawValue, iso2);
            if (suggestion) {
                this.formatSuggestion.emit(suggestion);
            }
        }
        // Batch zone operations and emissions
        this.runInZone(() => {
            this.onChange(parsed.e164);
            const changeEvent = { raw: rawValue, e164: parsed.e164, iso2 };
            // Emit both traditional and signal-based outputs
            this.inputChange.emit(changeEvent);
            this.inputChangeSignal.emit(changeEvent);
            // Trigger validation when input changes
            this.validatorChange?.();
        });
        // Mark for check to update view with OnPush (works in both zone and zoneless)
        this.cdr.markForCheck();
        const nsn = parsed.e164 ? this.nsnFromE164(parsed.e164, iso2) : digits;
        const formatWhenValid = this.formatWhenValidSignal() || this.formatWhenValid;
        const display = formatWhenValid === 'typing' ? this.displayValue(nsn, iso2) : nsn;
        if (display !== rawValue)
            this.setInputValue(display);
    }
    /** Convert any string to digits only (NSN basis). */
    toNSN(v) {
        return (v ?? '').replace(/\D/g, '');
    }
    /** Strip exactly one leading trunk '0' from national input. */
    stripLeadingZero(nsn) {
        return nsn.replace(/^0/, '');
    }
    /** Current country calling code (e.g. "44", "94"). */
    currentDialCode() {
        try {
            return (this.iti?.getSelectedCountryData?.()?.dialCode ?? '').toString();
        }
        catch (e) {
            // Return empty string if country data is unavailable
            return '';
        }
    }
    /** Convert E.164 (+<cc><nsn>) to NSN (never includes trunk '0'). */
    nsnFromE164(e164, iso2) {
        const dial = this.currentDialCode();
        if (!e164 || !dial)
            return this.toNSN(e164);
        if (e164.startsWith('+' + dial))
            return e164.slice(dial.length + 1);
        return this.toNSN(e164);
    }
    /** Format NSN for a region (adds spaces but NEVER a trunk '0'). */
    formatNSN(nsn, iso2) {
        try {
            const fmt = new AsYouType(iso2);
            return fmt.input(nsn);
        }
        catch (e) {
            // Return unformatted NSN if formatting fails
            return nsn;
        }
    }
    /** Compose visible value based on settings. */
    displayValue(nsn, iso2) {
        const nationalDisplay = this.nationalDisplaySignal() || this.nationalDisplay;
        return nationalDisplay === 'formatted' ? this.formatNSN(nsn, iso2) : nsn;
    }
    /**
     * Gets the current raw input value (as displayed, with formatting).
     * @returns The current input value as a string
     */
    currentRaw() {
        return this.isDestroyed ? '' : (this.inputRef?.nativeElement.value ?? '').trim();
    }
    /**
     * Gets the aria-describedby attribute value for accessibility.
     * @returns Space-separated list of element IDs that describe this input
     */
    getAriaDescribedBy() {
        const ids = [];
        const hasError = this.showError();
        if (this.hint && !hasError) {
            ids.push(this.resolvedId + '-hint');
        }
        if (hasError && this.errorText) {
            ids.push(this.resolvedId + '-error');
        }
        ids.push(this.resolvedId + '-status');
        return ids.length > 0 ? ids.join(' ') : null;
    }
    /**
     * Gets the ARIA status message for screen readers.
     * @returns Status message describing the current state
     */
    getAriaStatusMessage() {
        if (this.isDestroyed)
            return '';
        const raw = this.currentRaw();
        if (!raw)
            return '';
        const iso2 = this.currentIso2();
        const parsed = this.tel.parseWithInvalidDetection(raw, iso2);
        if (parsed.isValid && parsed.e164) {
            return `Valid phone number: ${parsed.e164}`;
        }
        else if (parsed.isInvalidInternational) {
            return 'Invalid country code';
        }
        else {
            return 'Invalid phone number';
        }
    }
    currentIso2() {
        if (this.isDestroyed)
            return 'US';
        try {
            const iso2 = (this.iti?.getSelectedCountryData?.()?.iso2 ?? this.initialCountry ?? 'US')
                .toString().toUpperCase();
            return iso2;
        }
        catch (e) {
            // Fallback to initial country or default if country data is unavailable
            return (this.initialCountry ?? 'US');
        }
    }
    setInputValue(v) {
        if (!this.isDestroyed && this.inputRef) {
            this.inputRef.nativeElement.value = v ?? '';
        }
    }
    isCurrentlyValid() {
        return this.isDestroyed ? false : this.tel.isValid(this.currentRaw(), this.currentIso2());
    }
    /** Make flag/dropdown non-interactive when disabled */
    applyDisabledUi(disabled) {
        if (this.isDestroyed)
            return;
        const input = this.inputRef?.nativeElement;
        if (!input)
            return;
        const flag = input.parentElement?.querySelector('.iti__selected-flag');
        if (flag) {
            flag.tabIndex = disabled ? -1 : 0;
            flag.setAttribute('aria-disabled', String(disabled));
        }
    }
    /** Returns true if nsn would be TOO_LONG for the current country. */
    wouldExceedMax(nsn, iso2) {
        if (this.isDestroyed)
            return false;
        try {
            const res = validatePhoneNumberLength(nsn, iso2);
            return res === 'TOO_LONG';
        }
        catch (e) {
            // Return false if validation fails (assume not too long)
            return false;
        }
    }
    /** Clean up event listeners to prevent memory leaks */
    cleanupEventListeners() {
        this.eventListeners.forEach(({ element, event, handler }) => {
            element.removeEventListener(event, handler);
        });
        this.eventListeners = [];
    }
    /** Detect and apply theme based on user preference and system settings */
    detectAndApplyTheme() {
        if (!isPlatformBrowser(this.platformId))
            return;
        let detectedTheme = 'light';
        // Fix precedence: Check signal first, but if it's 'auto' (default), fallback to legacy input
        // This allows [theme]="'light'" to work even if signal defaults to 'auto'
        const signalTheme = this.themeSignal();
        const theme = signalTheme !== 'auto' ? signalTheme : this.theme;
        if (theme === 'auto') {
            // Check for matchMedia support (not available in older browsers)
            try {
                if (window.matchMedia?.('(prefers-color-scheme: dark)').matches) {
                    detectedTheme = 'dark';
                }
            }
            catch (e) {
                // Fallback for browsers without matchMedia support
            }
            // Check for dark class on document element
            if (document.documentElement?.classList?.contains('dark')) {
                detectedTheme = 'dark';
            }
            // Check for data-theme attribute
            else if (document.documentElement?.getAttribute('data-theme') === 'dark') {
                detectedTheme = 'dark';
            }
        }
        else {
            detectedTheme = theme;
        }
        // Always apply theme (even if same) to ensure it's set on the element
        console.log(`[NgxsmkTelInput] Applying theme: ${detectedTheme} (Config: ${theme}, System Dark: ${typeof window !== 'undefined' && window.matchMedia?.('(prefers-color-scheme: dark)').matches})`);
        this.currentTheme = detectedTheme;
        this.applyTheme(detectedTheme);
    }
    /** Apply theme to the component */
    applyTheme(theme) {
        if (!isPlatformBrowser(this.platformId))
            return;
        const hostElement = this.hostElementRef?.nativeElement;
        if (hostElement) {
            // Set the theme attribute - this is the primary way CSS selects the theme
            hostElement.setAttribute('data-theme', theme);
            // Also add/remove dark class for additional CSS selector support
            if (theme === 'dark') {
                hostElement.classList.add('dark');
                hostElement.classList.remove('light');
            }
            else {
                hostElement.classList.add('light');
                hostElement.classList.remove('dark');
            }
            // Force style recalculation to ensure CSS is applied
            void hostElement.offsetHeight; // Trigger reflow
            // Mark for check to update view with OnPush strategy
            this.cdr.markForCheck();
        }
        else {
            // Retry if host element not available yet
            this.requestAnimationFrame(() => {
                if (!this.isDestroyed) {
                    this.applyTheme(theme);
                }
            });
            return;
        }
        this.applyCustomColors(theme);
        this.applyThemeToDropdown(theme);
    }
    applyCustomColors(theme) {
        if (!this.customColors || !this.customColors[theme])
            return;
        const p = this.customColors[theme];
        // Use hostElementRef since we used it above
        const hostElement = this.hostElementRef?.nativeElement;
        if (!hostElement)
            return;
        const style = hostElement.style;
        const set = (k, v) => { if (v)
            style.setProperty(k, v, 'important'); };
        set('--tel-bg', p.background);
        set('--tel-fg', p.foreground);
        set('--tel-border', p.border);
        set('--tel-border-hover', p.borderHover);
        set('--tel-ring', p.ring);
        set('--tel-placeholder', p.placeholder);
    }
    /** Apply theme to the dropdown if it exists */
    applyThemeToDropdown(theme) {
        if (!isPlatformBrowser(this.platformId))
            return;
        if (typeof document === 'undefined' || !document.querySelector)
            return;
        try {
            const dropdown = document.querySelector('.iti__country-list');
            if (dropdown && dropdown.setAttribute) {
                dropdown.setAttribute('data-theme', theme);
            }
        }
        catch (e) {
            // Fallback for browsers without querySelector support
        }
    }
    /**
     * Gets the current resolved theme (light or dark).
     * @returns The current theme ('light' or 'dark')
     */
    getCurrentTheme() {
        return this.currentTheme;
    }
    /**
     * Sets the theme programmatically.
     * @param theme - Theme to apply ('light' or 'dark')
     */
    setTheme(theme) {
        this.theme = theme;
        this.detectAndApplyTheme();
    }
    /** Update dropdown theme when it's opened */
    updateDropdownTheme() {
        if (!isPlatformBrowser(this.platformId))
            return;
        setTimeout(() => {
            const dropdown = document.querySelector('.iti__country-list');
            if (dropdown) {
                dropdown.setAttribute('data-theme', this.currentTheme);
                if (this.currentTheme === 'dark') {
                    dropdown.classList.add('dark-theme');
                    document.documentElement.classList.add('dark');
                    document.body.classList.add('dark');
                }
                else {
                    dropdown.classList.remove('dark-theme');
                    document.documentElement.classList.remove('dark');
                    document.body.classList.remove('dark');
                }
                const searchInput = dropdown.querySelector('.iti__search-input');
                if (searchInput) {
                    searchInput.setAttribute('data-theme', this.currentTheme);
                    if (this.currentTheme === 'dark') {
                        searchInput.classList.add('dark-theme');
                    }
                    else {
                        searchInput.classList.remove('dark-theme');
                    }
                    searchInput.style.pointerEvents = 'auto';
                    searchInput.style.opacity = '1';
                    searchInput.disabled = false;
                    // Add clear button functionality
                    this.setupSearchInputClearButton(searchInput);
                }
            }
        }, 10);
    }
    /** Setup clear button for search input */
    setupSearchInputClearButton(searchInput) {
        if (!isPlatformBrowser(this.platformId))
            return;
        // Clean up any existing listeners first
        this.cleanupSearchInputListeners();
        // Find the search container (could be parent or a wrapper)
        let searchContainer = searchInput.parentElement;
        if (!searchContainer)
            return;
        // Remove existing clear button if any
        const existingClear = searchContainer.querySelector('.iti__search-clear');
        if (existingClear) {
            existingClear.remove();
        }
        // Create clear button
        const clearButton = document.createElement('button');
        clearButton.type = 'button';
        clearButton.className = 'iti__search-clear';
        clearButton.setAttribute('aria-label', 'Clear search');
        clearButton.innerHTML = '×';
        clearButton.setAttribute('tabindex', '-1');
        // Make search input container relative if needed
        const containerStyle = window.getComputedStyle(searchContainer);
        if (containerStyle.position === 'static') {
            searchContainer.style.position = 'relative';
        }
        // Append clear button to container
        searchContainer.appendChild(clearButton);
        // Show/hide clear button based on input value
        const updateClearButton = () => {
            if (searchInput.value && searchInput.value.trim()) {
                clearButton.style.display = 'flex';
            }
            else {
                clearButton.style.display = 'none';
            }
        };
        // Clear input when button is clicked
        const handleClear = (e) => {
            e.preventDefault();
            e.stopPropagation();
            searchInput.value = '';
            // Trigger input event to update the country list
            searchInput.dispatchEvent(new Event('input', { bubbles: true }));
            searchInput.dispatchEvent(new Event('keyup', { bubbles: true }));
            searchInput.focus();
            updateClearButton();
        };
        const handleMousedown = (e) => e.preventDefault();
        const handlePaste = () => {
            setTimeout(updateClearButton, 0);
        };
        // Add event listeners and track cleanup functions
        clearButton.addEventListener('click', handleClear);
        this.searchInputCleanupFunctions.push(() => clearButton.removeEventListener('click', handleClear));
        clearButton.addEventListener('mousedown', handleMousedown);
        this.searchInputCleanupFunctions.push(() => clearButton.removeEventListener('mousedown', handleMousedown));
        // Update button visibility on input
        searchInput.addEventListener('input', updateClearButton);
        this.searchInputCleanupFunctions.push(() => searchInput.removeEventListener('input', updateClearButton));
        searchInput.addEventListener('keyup', updateClearButton);
        this.searchInputCleanupFunctions.push(() => searchInput.removeEventListener('keyup', updateClearButton));
        searchInput.addEventListener('focus', updateClearButton);
        this.searchInputCleanupFunctions.push(() => searchInput.removeEventListener('focus', updateClearButton));
        searchInput.addEventListener('paste', handlePaste);
        this.searchInputCleanupFunctions.push(() => searchInput.removeEventListener('paste', handlePaste));
        // Initial state
        updateClearButton();
    }
    /** Clean up search input event listeners to prevent memory leaks */
    cleanupSearchInputListeners() {
        this.searchInputCleanupFunctions.forEach(cleanup => cleanup());
        this.searchInputCleanupFunctions = [];
    }
    /** Setup observer to watch for dropdown changes and apply theme */
    setupDropdownThemeObserver() {
        if (!isPlatformBrowser(this.platformId))
            return;
        if (typeof window === 'undefined' || !window.MutationObserver)
            return;
        // Only create observer if it doesn't already exist
        if (this.themeObserver)
            return;
        try {
            this.themeObserver = new MutationObserver((mutations) => {
                mutations.forEach((mutation) => {
                    if (mutation.type === 'childList' && mutation.addedNodes) {
                        mutation.addedNodes.forEach((node) => {
                            if (node.nodeType === Node.ELEMENT_NODE || node.nodeType === 1) {
                                const element = node;
                                if (element.classList && element.classList.contains('iti__country-list')) {
                                    this.updateDropdownTheme();
                                }
                            }
                        });
                    }
                });
            });
            if (this.themeObserver && document.body) {
                this.themeObserver.observe(document.body, {
                    childList: true,
                    subtree: true
                });
            }
        }
        catch (e) {
            // Fallback for browsers without MutationObserver support
            this.themeObserver = null;
        }
    }
    /** Setup observer to watch for global theme changes on html/body */
    setupGlobalThemeObserver() {
        if (!isPlatformBrowser(this.platformId))
            return;
        // Watch for class changes on document.documentElement (html tag)
        // This supports Tailwind and other class-based theming systems
        const target = document.documentElement;
        if (!target || !window.MutationObserver)
            return;
        this.globalThemeObserver = new MutationObserver((mutations) => {
            // Only re-check if we are in auto mode
            const themeConfig = this.themeSignal() || this.theme;
            if (themeConfig === 'auto') {
                this.detectAndApplyTheme();
            }
        });
        this.globalThemeObserver.observe(target, {
            attributes: true,
            attributeFilter: ['class', 'data-theme']
        });
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgxsmkTelInputComponent, deps: [{ token: i0.NgZone, optional: true }, { token: NgxsmkTelInputService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: NgxsmkTelInputComponent, isStandalone: true, selector: "ngxsmk-tel-input", inputs: { initialCountrySignal: { classPropertyName: "initialCountrySignal", publicName: "initialCountrySignal", isSignal: true, isRequired: false, transformFunction: null }, preferredCountriesSignal: { classPropertyName: "preferredCountriesSignal", publicName: "preferredCountriesSignal", isSignal: true, isRequired: false, transformFunction: null }, onlyCountriesSignal: { classPropertyName: "onlyCountriesSignal", publicName: "onlyCountriesSignal", isSignal: true, isRequired: false, transformFunction: null }, separateDialCodeSignal: { classPropertyName: "separateDialCodeSignal", publicName: "separateDialCodeSignal", isSignal: true, isRequired: false, transformFunction: null }, allowDropdownSignal: { classPropertyName: "allowDropdownSignal", publicName: "allowDropdownSignal", isSignal: true, isRequired: false, transformFunction: null }, nationalDisplaySignal: { classPropertyName: "nationalDisplaySignal", publicName: "nationalDisplaySignal", isSignal: true, isRequired: false, transformFunction: null }, formatWhenValidSignal: { classPropertyName: "formatWhenValidSignal", publicName: "formatWhenValidSignal", isSignal: true, isRequired: false, transformFunction: null }, sizeSignal: { classPropertyName: "sizeSignal", publicName: "sizeSignal", isSignal: true, isRequired: false, transformFunction: null }, variantSignal: { classPropertyName: "variantSignal", publicName: "variantSignal", isSignal: true, isRequired: false, transformFunction: null }, themeSignal: { classPropertyName: "themeSignal", publicName: "themeSignal", isSignal: true, isRequired: false, transformFunction: null }, disabledSignal: { classPropertyName: "disabledSignal", publicName: "disabledSignal", isSignal: true, isRequired: false, transformFunction: null }, initialCountry: { classPropertyName: "initialCountry", publicName: "initialCountry", isSignal: false, isRequired: false, transformFunction: null }, preferredCountries: { classPropertyName: "preferredCountries", publicName: "preferredCountries", isSignal: false, isRequired: false, transformFunction: null }, onlyCountries: { classPropertyName: "onlyCountries", publicName: "onlyCountries", isSignal: false, isRequired: false, transformFunction: null }, separateDialCode: { classPropertyName: "separateDialCode", publicName: "separateDialCode", isSignal: false, isRequired: false, transformFunction: null }, allowDropdown: { classPropertyName: "allowDropdown", publicName: "allowDropdown", isSignal: false, isRequired: false, transformFunction: null }, nationalDisplay: { classPropertyName: "nationalDisplay", publicName: "nationalDisplay", isSignal: false, isRequired: false, transformFunction: null }, formatWhenValid: { classPropertyName: "formatWhenValid", publicName: "formatWhenValid", isSignal: false, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: false, isRequired: false, transformFunction: null }, autocomplete: { classPropertyName: "autocomplete", publicName: "autocomplete", isSignal: false, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: false, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: false, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: false, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: false, isRequired: false, transformFunction: null }, errorText: { classPropertyName: "errorText", publicName: "errorText", isSignal: false, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: false, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: false, isRequired: false, transformFunction: null }, showClear: { classPropertyName: "showClear", publicName: "showClear", isSignal: false, isRequired: false, transformFunction: null }, autoFocus: { classPropertyName: "autoFocus", publicName: "autoFocus", isSignal: false, isRequired: false, transformFunction: null }, selectOnFocus: { classPropertyName: "selectOnFocus", publicName: "selectOnFocus", isSignal: false, isRequired: false, transformFunction: null }, showErrorWhenTouched: { classPropertyName: "showErrorWhenTouched", publicName: "showErrorWhenTouched", isSignal: false, isRequired: false, transformFunction: null }, dropdownAttachToBody: { classPropertyName: "dropdownAttachToBody", publicName: "dropdownAttachToBody", isSignal: false, isRequired: false, transformFunction: null }, dropdownZIndex: { classPropertyName: "dropdownZIndex", publicName: "dropdownZIndex", isSignal: false, isRequired: false, transformFunction: null }, i18n: { classPropertyName: "i18n", publicName: "i18n", isSignal: false, isRequired: false, transformFunction: null }, telI18n: { classPropertyName: "telI18n", publicName: "telI18n", isSignal: false, isRequired: false, transformFunction: null }, localizedCountries: { classPropertyName: "localizedCountries", publicName: "localizedCountries", isSignal: false, isRequired: false, transformFunction: null }, telLocalizedCountries: { classPropertyName: "telLocalizedCountries", publicName: "telLocalizedCountries", isSignal: false, isRequired: false, transformFunction: null }, clearAriaLabel: { classPropertyName: "clearAriaLabel", publicName: "clearAriaLabel", isSignal: false, isRequired: false, transformFunction: null }, dir: { classPropertyName: "dir", publicName: "dir", isSignal: false, isRequired: false, transformFunction: null }, autoPlaceholder: { classPropertyName: "autoPlaceholder", publicName: "autoPlaceholder", isSignal: false, isRequired: false, transformFunction: null }, utilsScript: { classPropertyName: "utilsScript", publicName: "utilsScript", isSignal: false, isRequired: false, transformFunction: null }, customPlaceholder: { classPropertyName: "customPlaceholder", publicName: "customPlaceholder", isSignal: false, isRequired: false, transformFunction: null }, digitsOnly: { classPropertyName: "digitsOnly", publicName: "digitsOnly", isSignal: false, isRequired: false, transformFunction: null }, lockWhenValid: { classPropertyName: "lockWhenValid", publicName: "lockWhenValid", isSignal: false, isRequired: false, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: false, isRequired: false, transformFunction: null }, customColors: { classPropertyName: "customColors", publicName: "customColors", isSignal: false, isRequired: false, transformFunction: null }, enableIntelligence: { classPropertyName: "enableIntelligence", publicName: "enableIntelligence", isSignal: false, isRequired: false, transformFunction: null }, enableFormatSuggestions: { classPropertyName: "enableFormatSuggestions", publicName: "enableFormatSuggestions", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { countryChangeSignal: "countryChangeSignal", validityChangeSignal: "validityChangeSignal", inputChangeSignal: "inputChangeSignal", countryChange: "countryChange", validityChange: "validityChange", inputChange: "inputChange", intelligenceChange: "intelligenceChange", formatSuggestion: "formatSuggestion" }, providers: [
            { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NgxsmkTelInputComponent), multi: true },
            { provide: NG_VALIDATORS, useExisting: forwardRef(() => NgxsmkTelInputComponent), multi: true }
        ], viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["telInput"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: `
      <div class="ngxsmk-tel"
         [class.disabled]="disabledSignal() || disabled"
         [attr.data-size]="sizeSignal() || size"
         [attr.data-variant]="variantSignal() || variant"
         [attr.dir]="dir"
         [attr.aria-label]="label || 'Phone number input'">
      @if (label) {
        <label class="ngxsmk-tel__label" [for]="resolvedId">{{ label }}</label>
      }

      <div class="ngxsmk-tel__wrap" 
           [class.has-error]="showError()"
           [attr.aria-describedby]="getAriaDescribedBy()">
        <div class="ngxsmk-tel-input__wrapper">
          <input
            #telInput
            type="tel"
            class="ngxsmk-tel-input__control"
            [id]="resolvedId"
            [attr.name]="name || null"
            [attr.placeholder]="placeholder || null"
            [attr.autocomplete]="autocomplete"
            [attr.inputmode]="digitsOnly ? 'numeric' : 'tel'"
            [disabled]="disabledSignal() || disabled"
            [attr.aria-invalid]="showError() ? 'true' : 'false'"
            [attr.aria-required]="isRequired ? 'true' : null"
            [attr.aria-describedby]="getAriaDescribedBy()"
            [attr.aria-errormessage]="showError() && errorText ? resolvedId + '-error' : null"
            (blur)="onBlur()"
            (focus)="onFocus()"
          />
        </div>

        @if (showClear && (rawValue() || currentRaw())) {
          <button type="button"
                  class="ngxsmk-tel__clear"
                  (click)="clearInput()"
                  [attr.aria-label]="clearAriaLabel"
                  [attr.aria-describedby]="resolvedId">
            ×
          </button>
        }
      </div>

      @if (hint && !showError()) {
        <div class="ngxsmk-tel__hint" [id]="resolvedId + '-hint'">{{ hint }}</div>
      }
      @if (showError() && errorText) {
        <div class="ngxsmk-tel__error" 
             [id]="resolvedId + '-error'"
             role="alert"
             [attr.aria-live]="'polite'">{{ errorText }}</div>
      }
      <div [id]="resolvedId + '-status'" 
           class="sr-only" 
           role="status" 
           [attr.aria-live]="'polite'"
           [attr.aria-atomic]="true">{{ getAriaStatusMessage() }}</div>
    </div>
  `, isInline: true, styles: [":host{--tel-bg: #fff;--tel-fg: #0f172a;--tel-border: #c0c0c0;--tel-border-hover: #9aa0a6;--tel-ring: #2563eb;--tel-placeholder: #9ca3af;--tel-error: #ef4444;--tel-success: #10b981;--tel-warning: #f59e0b;--tel-radius: 8px;--tel-focus-shadow: 0 0 0 2px rgba(37, 99, 235, .2);--tel-dd-bg: #fff;--tel-dd-border: var(--tel-border);--tel-dd-shadow: 0 24px 60px rgba(0, 0, 0, .18);--tel-dd-radius: 8px;--tel-dd-item-hover: rgba(37, 99, 235, .08);--tel-dd-z: 2000;--tel-dd-search-bg: rgba(148, 163, 184, .08);display:block;contain:layout style;isolation:isolate}:host-context(.dark):not([data-theme=light]):not(.light),:host([data-theme=dark]),:host(.dark){--tel-bg: #0f172a;--tel-fg: #e2e8f0;--tel-border: #334155;--tel-border-hover: #475569;--tel-ring: #60a5fa;--tel-placeholder: #94a3b8;--tel-error: #f87171;--tel-success: #34d399;--tel-warning: #fbbf24;--tel-focus-shadow: 0 0 0 .2rem rgba(96, 165, 250, .25);--tel-dd-bg: #1e293b;--tel-dd-border: #334155;--tel-dd-shadow: 0 24px 60px rgba(0, 0, 0, .4);--tel-dd-search-bg: rgba(148, 163, 184, .12)}:host([data-theme=light]),:host(.light){--tel-bg: #fff !important;--tel-fg: #0f172a !important;--tel-border: #c0c0c0 !important;--tel-border-hover: #9aa0a6 !important;--tel-ring: #2563eb !important;--tel-placeholder: #9ca3af !important;--tel-error: #ef4444 !important;--tel-success: #10b981 !important;--tel-warning: #f59e0b !important;--tel-focus-shadow: 0 0 0 2px rgba(37, 99, 235, .2) !important;--tel-dd-bg: #fff !important;--tel-dd-border: #c0c0c0 !important;--tel-dd-shadow: 0 24px 60px rgba(0, 0, 0, .18) !important;--tel-dd-search-bg: rgba(148, 163, 184, .08) !important}:host-context(.dark):not([data-theme=light]):not(.light) ::ng-deep .iti__country-list,:host([data-theme=dark]) ::ng-deep .iti__country-list,:host(.dark) ::ng-deep .iti__country-list{background:var(--tel-dd-bg)!important;border-color:var(--tel-dd-border)!important;color:#e2e8f0!important}:host-context(.dark):not([data-theme=light]):not(.light) ::ng-deep .iti__search-input,:host([data-theme=dark]) ::ng-deep .iti__search-input,:host(.dark) ::ng-deep .iti__search-input{background:var(--tel-dd-search-bg)!important;color:#fff!important;border-bottom-color:var(--tel-dd-border)!important}:host-context(.dark):not([data-theme=light]):not(.light) ::ng-deep .iti__country,:host([data-theme=dark]) ::ng-deep .iti__country,:host(.dark) ::ng-deep .iti__country{color:#e2e8f0!important}:host-context(.dark):not([data-theme=light]):not(.light) ::ng-deep .iti__country.iti__highlight,:host([data-theme=dark]) ::ng-deep .iti__country.iti__highlight,:host(.dark) ::ng-deep .iti__country.iti__highlight{background-color:var(--tel-dd-item-hover)!important}:host-context(.dark):not([data-theme=light]):not(.light) ::ng-deep .iti__country-name,:host([data-theme=dark]) ::ng-deep .iti__country-name,:host(.dark) ::ng-deep .iti__country-name{color:#e2e8f0!important}:host-context(.dark):not([data-theme=light]):not(.light) ::ng-deep .iti__country-code,:host([data-theme=dark]) ::ng-deep .iti__country-code,:host(.dark) ::ng-deep .iti__country-code{color:#94a3b8!important}:host-context(.dark):not([data-theme=light]) ::ng-deep .iti__dial-code,:host([data-theme=dark]) ::ng-deep .iti__dial-code,:host(.dark) ::ng-deep .iti__dial-code{color:#94a3b8!important}:host-context(.dark):not([data-theme=light]):not(.light) ::ng-deep .iti__arrow,:host([data-theme=dark]) ::ng-deep .iti__arrow,:host(.dark) ::ng-deep .iti__arrow{border-top-color:#e2e8f0!important;opacity:1}:host-context(.dark):not([data-theme=light]):not(.light) ::ng-deep .iti__arrow.iti__arrow--up,:host([data-theme=dark]) ::ng-deep .iti__arrow.iti__arrow--up,:host(.dark) ::ng-deep .iti__arrow.iti__arrow--up{border-top-color:transparent!important;border-bottom-color:#e2e8f0!important}.ngxsmk-tel{width:100%;color:var(--tel-fg)}.ngxsmk-tel.disabled{opacity:.7;cursor:not-allowed}.ngxsmk-tel__label{display:inline-block;margin-bottom:8px;font-size:.875rem;font-weight:500;color:var(--tel-fg)}.ngxsmk-tel__wrap{position:relative}.ngxsmk-tel-input__wrapper,:host ::ng-deep .iti{width:100%}.ngxsmk-tel-input__control{width:100%;height:40px;font:inherit;color:var(--tel-fg);background:var(--tel-bg);border:1px solid var(--tel-border);-webkit-border-radius:var(--tel-radius);-moz-border-radius:var(--tel-radius);border-radius:var(--tel-radius);padding:10px 40px 10px 12px;outline:none;-webkit-transition:border-color .2s cubic-bezier(.4,0,.2,1),box-shadow .2s cubic-bezier(.4,0,.2,1),background .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1);-moz-transition:border-color .2s cubic-bezier(.4,0,.2,1),box-shadow .2s cubic-bezier(.4,0,.2,1),background .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1);-o-transition:border-color .2s cubic-bezier(.4,0,.2,1),box-shadow .2s cubic-bezier(.4,0,.2,1),background .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1);transition:border-color .2s cubic-bezier(.4,0,.2,1),box-shadow .2s cubic-bezier(.4,0,.2,1),background .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1);will-change:border-color,box-shadow,background,transform;-webkit-transform:translateZ(0);transform:translateZ(0);box-shadow:0 1px 3px #0000001a;font-size:16px;line-height:1.5;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.ngxsmk-tel-input__control::placeholder{color:var(--tel-placeholder)}.ngxsmk-tel-input__control:hover:not(:disabled):not(:focus){border-color:var(--tel-border-hover);box-shadow:0 2px 4px #00000014,0 1px 2px #0000000a;transform:translateY(-1px)}.ngxsmk-tel-input__control:focus{border-color:var(--tel-ring);box-shadow:var(--tel-focus-shadow),0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f;background:var(--tel-bg);color:var(--tel-fg);transform:translateY(0)}[data-size=sm] .ngxsmk-tel-input__control{height:34px;font-size:13px;padding:6px 36px 6px 10px;border-radius:6px}[data-size=sm] :host ::ng-deep .iti__country-list,[data-size=sm] :host ::ng-deep .iti__search-input,[data-size=sm] :host ::ng-deep .iti__country,[data-size=sm] :host ::ng-deep .iti__country-name,[data-size=sm] :host ::ng-deep .iti__country-code,[data-size=sm] :host ::ng-deep .iti__dial-code{font-size:13px}[data-size=lg] .ngxsmk-tel-input__control{height:46px;font-size:16px;padding:12px 44px 12px 14px;border-radius:10px}[data-size=lg] :host ::ng-deep .iti__country-list,[data-size=lg] :host ::ng-deep .iti__search-input,[data-size=lg] :host ::ng-deep .iti__country,[data-size=lg] :host ::ng-deep .iti__country-name,[data-size=lg] :host ::ng-deep .iti__country-code,[data-size=lg] :host ::ng-deep .iti__dial-code{font-size:16px}:host ::ng-deep .iti__country-list,:host ::ng-deep .iti__search-input,:host ::ng-deep .iti__country,:host ::ng-deep .iti__country-name,:host ::ng-deep .iti__country-code,:host ::ng-deep .iti__dial-code{font-size:15px}[data-variant=filled] .ngxsmk-tel-input__control{background:#94a3b814}[data-variant=underline] .ngxsmk-tel-input__control{border:0;border-bottom:2px solid var(--tel-border);border-radius:0;padding-left:0;padding-right:34px}[data-variant=underline] .ngxsmk-tel-input__control:focus{border-bottom-color:var(--tel-ring);box-shadow:none}:host ::ng-deep .iti__flag-container{border-top-left-radius:var(--tel-radius);border-bottom-left-radius:var(--tel-radius);border:1px solid var(--tel-border);border-right:none;background:var(--tel-bg)}:host ::ng-deep .iti__selected-flag{height:100%;padding:0 10px;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;outline:none!important;border:none!important;box-shadow:none!important}:host ::ng-deep .iti__selected-flag:focus,:host ::ng-deep .iti__selected-flag:active,:host ::ng-deep .iti__selected-flag:focus-visible{outline:none!important;border:none!important;box-shadow:none!important}:host ::ng-deep .iti__selected-country{z-index:1;position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:100%;background:none;border:0;margin:0;padding:0;font-family:inherit;font-size:inherit;color:inherit;border-radius:0;font-weight:inherit;line-height:inherit;text-decoration:none;outline:none!important}:host ::ng-deep .iti__selected-country:focus,:host ::ng-deep .iti__selected-country:active,:host ::ng-deep .iti__selected-country:focus-visible{outline:none!important}:host ::ng-deep .iti__country-list{background:var(--tel-dd-bg);border:1px solid var(--tel-dd-border);-webkit-border-radius:var(--tel-dd-radius);-moz-border-radius:var(--tel-dd-radius);border-radius:var(--tel-dd-radius);box-shadow:var(--tel-dd-shadow);max-height:360px;max-height:min(50vh,360px);overflow:auto;padding:6px 0;width:100%;min-width:0;box-sizing:border-box;z-index:var(--tel-dd-z);contain:layout style;isolation:isolate;will-change:transform;color:var(--tel-fg);display:block;animation:slideDown .2s cubic-bezier(.4,0,.2,1)}@keyframes slideDown{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}:host ::ng-deep .iti--container .iti__country-list{z-index:var(--tel-dd-z);width:100%;min-width:0;box-sizing:border-box}:host ::ng-deep .iti__search-input{position:-webkit-sticky;position:sticky;top:0;margin:0;padding:10px 36px 10px 12px;width:100%;border:0;border-bottom:1px solid var(--tel-dd-border);outline:none;background:var(--tel-dd-search-bg);color:var(--tel-fg);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:host ::ng-deep .iti__search-box,:host ::ng-deep .iti__country-list>div:first-child{position:relative}:host ::ng-deep .iti__search-clear{position:absolute;right:8px;top:50%;transform:translateY(-50%);background:transparent;border:0;cursor:pointer;font-size:18px;line-height:1;width:24px;height:24px;display:flex;align-items:center;justify-content:center;color:var(--tel-placeholder);padding:0;z-index:10;transition:color .2s ease;-webkit-tap-highlight-color:transparent}:host ::ng-deep .iti__search-clear:hover{color:var(--tel-fg)}:host ::ng-deep .iti__search-clear:active{opacity:.7}:host ::ng-deep .iti__search-input::placeholder{color:var(--tel-placeholder)}:host ::ng-deep .iti__country{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:10px 12px;cursor:pointer;color:var(--tel-fg);transition:background-color .15s cubic-bezier(.4,0,.2,1),transform .15s cubic-bezier(.4,0,.2,1)}@supports (display: grid){:host ::ng-deep .iti__country{display:grid;grid-template-columns:28px 1fr auto;align-items:center;column-gap:.5rem}}:host ::ng-deep .iti__country.iti__highlight{background-color:var(--tel-dd-item-hover);transform:scale(.99)}:host ::ng-deep .iti__dial-code{color:var(--tel-placeholder);font-weight:600;margin-left:10px}:host ::ng-deep .iti__country-name{color:var(--tel-fg)}:host ::ng-deep .iti__country-code{color:var(--tel-placeholder);font-weight:500}.ngxsmk-tel__clear{position:absolute;right:8px;top:50%;transform:translateY(-50%);border:0;background:transparent;font-size:18px;line-height:1;width:28px;height:28px;border-radius:50%;cursor:pointer;color:var(--tel-placeholder);transition:color .2s ease}.ngxsmk-tel__clear:hover{color:var(--tel-fg)}.ngxsmk-tel__hint{margin-top:8px;font-size:12px;color:var(--tel-placeholder)}.ngxsmk-tel__error{margin-top:8px;font-size:12px;color:var(--tel-error)}.ngxsmk-tel__wrap.has-error .ngxsmk-tel-input__control{border-color:var(--tel-error);box-shadow:0 0 0 3px #ef444426}.ngxsmk-tel.disabled .iti__flag-container,.ngxsmk-tel.disabled .iti__selected-flag{pointer-events:none;opacity:.6}:host-context(.dark):not([data-theme=light]) .ngxsmk-tel-input__control,:host([data-theme=dark]) .ngxsmk-tel-input__control{background:#0f172a!important;color:#e2e8f0!important;border-color:#334155!important;box-shadow:0 1px 3px #0000004d!important}:host-context(.dark):not([data-theme=light]) .ngxsmk-tel-input__control:focus,:host([data-theme=dark]) .ngxsmk-tel-input__control:focus{background:#0f172a!important;color:#e2e8f0!important;border-color:#60a5fa!important;box-shadow:0 0 0 .2rem #60a5fa40!important}:host-context(.dark):not([data-theme=light]) .ngxsmk-tel-input__control::placeholder,:host([data-theme=dark]) .ngxsmk-tel-input__control::placeholder{color:#94a3b8!important;opacity:1}:host-context(.dark):not([data-theme=light]) .ngxsmk-tel__label,:host([data-theme=dark]) .ngxsmk-tel__label{color:#e2e8f0!important}:host-context(.dark):not([data-theme=light]) .ngxsmk-tel__hint,:host([data-theme=dark]) .ngxsmk-tel__hint{color:#94a3b8!important;opacity:1}:host-context(.dark):not([data-theme=light]) .ngxsmk-tel__error,:host([data-theme=dark]) .ngxsmk-tel__error{color:#f87171!important}:host-context(.dark):not([data-theme=light]) .ngxsmk-tel__clear,:host([data-theme=dark]) .ngxsmk-tel__clear{color:#94a3b8!important;opacity:1}:host-context(.dark):not([data-theme=light]) .ngxsmk-tel__clear:hover,:host([data-theme=dark]) .ngxsmk-tel__clear:hover{color:#e2e8f0!important;opacity:1}:host-context(.dark):not([data-theme=light]) ::ng-deep .iti__search-input::placeholder,:host([data-theme=dark]) ::ng-deep .iti__search-input::placeholder{color:#94a3b8!important;opacity:1}:host-context(.dark):not([data-theme=light]) ::ng-deep .iti__search-clear,:host([data-theme=dark]) ::ng-deep .iti__search-clear{color:#94a3b8!important;opacity:1}:host-context(.dark):not([data-theme=light]) ::ng-deep .iti__search-clear:hover,:host([data-theme=dark]) ::ng-deep .iti__search-clear:hover{color:#e2e8f0!important;opacity:1}:host-context(.dark):not([data-theme=light]) ::ng-deep .iti__selected-dial-code,:host([data-theme=dark]) ::ng-deep .iti__selected-dial-code{color:#e2e8f0!important}:host-context(.dark):not([data-theme=light]) ::ng-deep .iti__selected-flag,:host([data-theme=dark]) ::ng-deep .iti__selected-flag{color:#e2e8f0!important}:host([data-theme=light]) .ngxsmk-tel-input__control{background:#fff!important;background-color:#fff!important;color:#0f172a!important;border-color:silver!important;box-shadow:0 1px 3px #0000001a!important}:host([data-theme=light]) .ngxsmk-tel-input__control:focus{background:#fff!important;color:#0f172a!important;border-color:#2563eb!important;box-shadow:0 0 0 3px #2563eb40!important}:host([data-theme=light]) .ngxsmk-tel-input__control::placeholder{color:#9ca3af!important;opacity:1}:host([data-theme=light]) .ngxsmk-tel__label{color:#0f172a!important}:host([data-theme=light]) .ngxsmk-tel__hint{color:#6b7280!important;opacity:1}:host([data-theme=light]) .ngxsmk-tel__error{color:#ef4444!important}:host([data-theme=light]) .ngxsmk-tel__clear{color:#6b7280!important;opacity:1}:host([data-theme=light]) .ngxsmk-tel__clear:hover{color:#0f172a!important;opacity:1}:host([data-theme=light]) ::ng-deep .iti__search-input{background:#94a3b814!important;color:#0f172a!important;border-bottom-color:silver!important}:host([data-theme=light]) ::ng-deep .iti__search-input::placeholder{color:#9ca3af!important;opacity:1}:host([data-theme=light]) ::ng-deep .iti__search-clear{color:#6b7280!important;opacity:1}:host([data-theme=light]) ::ng-deep .iti__search-clear:hover{color:#0f172a!important;opacity:1}:host([data-theme=light]) ::ng-deep .iti__selected-dial-code{color:#6b7280!important}:host([data-theme=light]) ::ng-deep .iti__selected-flag{color:#0f172a!important}:host([data-theme=light]) ::ng-deep .iti__arrow{border-top-color:#0f172a!important;opacity:1}:host([data-theme=light]) ::ng-deep .iti__arrow:hover{opacity:1}:host([data-theme=light]) ::ng-deep .iti--allow-dropdown .iti__arrow{border-top-color:#0f172a!important}:host([data-theme=light]) ::ng-deep .iti__country-list{background:#fff!important;border-color:silver!important;color:#0f172a!important}:host([data-theme=light]) ::ng-deep .iti__country{color:#0f172a!important}:host([data-theme=light]) ::ng-deep .iti__country-name{color:#0f172a!important}:host([data-theme=light]) ::ng-deep .iti__country-code{color:#6b7280!important}:host([data-theme=light]) ::ng-deep .iti__dial-code{color:#6b7280!important}:host([data-theme=light]) ::ng-deep .iti__flag-container{background:#fff!important;border-color:silver!important}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}@media (max-width: 768px){.ngxsmk-tel__wrap{position:relative;width:100%;max-width:100%;overflow:visible}:host{width:100%;max-width:100%;display:block}.ngxsmk-tel{width:100%;max-width:100%}.ngxsmk-tel-input__wrapper,:host ::ng-deep .iti{width:100%!important;max-width:100%!important;box-sizing:border-box}.ngxsmk-tel-input__control{font-size:16px!important;padding:12px 44px 12px 12px;min-height:44px;width:100%!important;max-width:100%!important;box-sizing:border-box}.ngxsmk-tel__clear{width:44px;height:44px;min-width:44px;min-height:44px;right:4px;padding:8px;display:flex;align-items:center;justify-content:center;font-size:18px}:host ::ng-deep .iti__selected-flag{min-width:44px;min-height:44px;padding:0 12px;touch-action:manipulation;font-size:14px}:host ::ng-deep .iti__flag-box{width:20px;height:15px}:host ::ng-deep .iti__country-list{width:100%!important;max-width:100%!important;min-width:0!important;max-height:400px;max-height:min(70vh,400px);-webkit-overflow-scrolling:touch;overflow-x:hidden;position:absolute!important;top:100%!important;left:0!important;right:0!important;transform:none!important;margin-top:4px!important;box-shadow:0 4px 12px #00000026!important;box-sizing:border-box}:host ::ng-deep .iti--container{position:relative!important;width:100%!important;max-width:100%!important;box-sizing:border-box}:host ::ng-deep .iti__dropdown{position:relative!important;width:100%!important;box-sizing:border-box}:host ::ng-deep .iti__country-list{width:100%!important;min-width:0!important;max-width:100%!important;box-sizing:border-box}:host ::ng-deep .iti__search-input{padding-right:36px!important}:host ::ng-deep .iti__search-clear{width:28px!important;height:28px!important;font-size:20px!important;right:6px!important}:host ::ng-deep .iti__country{min-height:48px;padding:12px 14px;font-size:15px;box-sizing:border-box;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}@supports (display: grid){:host ::ng-deep .iti__country{display:grid;grid-template-columns:28px 1fr auto;column-gap:.625rem}}:host ::ng-deep .iti__country-name{font-size:15px!important;line-height:1.4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host ::ng-deep .iti__country-code{font-size:13px!important;line-height:1.4}:host ::ng-deep .iti__dial-code{font-size:14px!important;line-height:1.4;margin-left:8px;white-space:nowrap}:host ::ng-deep .iti__search-input{font-size:16px!important;padding:12px 14px;min-height:44px;width:100%!important;box-sizing:border-box}.ngxsmk-tel__label{font-size:.9375rem;margin-bottom:8px;line-height:1.4}.ngxsmk-tel__hint,.ngxsmk-tel__error{font-size:.8125rem;margin-top:8px;line-height:1.4}[data-size=sm] .ngxsmk-tel-input__control{min-height:40px;font-size:16px!important;padding:10px 40px 10px 10px;width:100%!important;max-width:100%!important;box-sizing:border-box}[data-size=lg] .ngxsmk-tel-input__control{min-height:48px;font-size:16px!important;padding:14px 48px 14px 14px;width:100%!important;max-width:100%!important;box-sizing:border-box}[data-variant=underline] .ngxsmk-tel-input__control{padding-right:40px;min-height:44px;width:100%!important;max-width:100%!important;box-sizing:border-box}:host ::ng-deep .iti__flag-container{max-width:100%;overflow:hidden}:host ::ng-deep .iti__selected-dial-code{font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}}@media (max-width: 480px){:host{width:100%;max-width:100%}.ngxsmk-tel,.ngxsmk-tel__wrap{width:100%;max-width:100%}.ngxsmk-tel-input__wrapper,:host ::ng-deep .iti{width:100%!important;max-width:100%!important}.ngxsmk-tel-input__control{padding:10px 40px 10px 10px;font-size:16px!important;width:100%!important;max-width:100%!important;box-sizing:border-box}:host ::ng-deep .iti__selected-flag{padding:0 8px;min-width:40px;font-size:13px}:host ::ng-deep .iti__flag-box{width:18px;height:14px}:host ::ng-deep .iti__country-list{max-height:350px;max-height:min(60vh,350px);border-radius:8px;position:absolute!important;top:100%!important;left:0!important;right:0!important;transform:none!important;margin-top:4px!important;width:100%!important;max-width:100%!important;box-sizing:border-box}:host ::ng-deep .iti__search-input{padding-right:36px!important}:host ::ng-deep .iti__search-clear{width:24px!important;height:24px!important;font-size:18px!important;right:6px!important}:host ::ng-deep .iti__country{padding:10px 12px;min-height:44px;font-size:14px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}@supports (display: grid){:host ::ng-deep .iti__country{display:grid;grid-template-columns:26px 1fr auto;column-gap:.5rem}}:host ::ng-deep .iti__country-name{font-size:14px!important}:host ::ng-deep .iti__country-code{font-size:12px!important}:host ::ng-deep .iti__dial-code{font-size:13px!important;margin-left:6px}:host ::ng-deep .iti__search-input{font-size:16px!important;padding:10px 12px;min-height:44px}.ngxsmk-tel__clear{width:40px;height:40px;min-width:40px;min-height:40px;font-size:16px;right:2px}.ngxsmk-tel__label{font-size:.875rem;margin-bottom:6px;line-height:1.4}.ngxsmk-tel__hint,.ngxsmk-tel__error{font-size:.75rem;line-height:1.4}:host ::ng-deep .iti__flag-container{max-width:100%;overflow:hidden}:host ::ng-deep .iti__selected-dial-code{font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:60px}[data-size=sm] :host ::ng-deep .iti__country-name,[data-size=sm] :host ::ng-deep .iti__country-code,[data-size=sm] :host ::ng-deep .iti__dial-code{font-size:13px!important}[data-size=lg] :host ::ng-deep .iti__country-name,[data-size=lg] :host ::ng-deep .iti__country-code,[data-size=lg] :host ::ng-deep .iti__dial-code{font-size:15px!important}}@media (max-width: 768px) and (orientation: landscape){:host ::ng-deep .iti__country-list{max-height:300px;max-height:min(50vh,300px)}}@media (min-width: 481px) and (max-width: 1024px){.ngxsmk-tel-input__control{padding:11px 42px 11px 12px}:host ::ng-deep .iti__country-list{max-height:400px;max-height:min(60vh,400px)}}@media (hover: none) and (pointer: coarse){.ngxsmk-tel__clear{width:44px;height:44px;min-width:44px;min-height:44px}:host ::ng-deep .iti__selected-flag{min-width:44px;min-height:44px}:host ::ng-deep .iti__country{min-height:48px}:host ::ng-deep .iti__country:active{background-color:var(--tel-dd-item-hover)}.ngxsmk-tel__clear:active{background-color:#0000001a;transform:translateY(-50%) scale(.95)}}@media (-webkit-min-device-pixel-ratio: 2),(min-resolution: 192dpi){.ngxsmk-tel-input__control{border-width:.5px}}@media screen and (max-width: 768px){.ngxsmk-tel-input__control{-webkit-text-size-adjust:100%;text-size-adjust:100%}}@supports (padding: max(0px)){@media (max-width: 768px){:host ::ng-deep .iti__country-list{padding-left:max(6px,env(safe-area-inset-left));padding-right:max(6px,env(safe-area-inset-right))}}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgxsmkTelInputComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ngxsmk-tel-input', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: `
      <div class="ngxsmk-tel"
         [class.disabled]="disabledSignal() || disabled"
         [attr.data-size]="sizeSignal() || size"
         [attr.data-variant]="variantSignal() || variant"
         [attr.dir]="dir"
         [attr.aria-label]="label || 'Phone number input'">
      @if (label) {
        <label class="ngxsmk-tel__label" [for]="resolvedId">{{ label }}</label>
      }

      <div class="ngxsmk-tel__wrap" 
           [class.has-error]="showError()"
           [attr.aria-describedby]="getAriaDescribedBy()">
        <div class="ngxsmk-tel-input__wrapper">
          <input
            #telInput
            type="tel"
            class="ngxsmk-tel-input__control"
            [id]="resolvedId"
            [attr.name]="name || null"
            [attr.placeholder]="placeholder || null"
            [attr.autocomplete]="autocomplete"
            [attr.inputmode]="digitsOnly ? 'numeric' : 'tel'"
            [disabled]="disabledSignal() || disabled"
            [attr.aria-invalid]="showError() ? 'true' : 'false'"
            [attr.aria-required]="isRequired ? 'true' : null"
            [attr.aria-describedby]="getAriaDescribedBy()"
            [attr.aria-errormessage]="showError() && errorText ? resolvedId + '-error' : null"
            (blur)="onBlur()"
            (focus)="onFocus()"
          />
        </div>

        @if (showClear && (rawValue() || currentRaw())) {
          <button type="button"
                  class="ngxsmk-tel__clear"
                  (click)="clearInput()"
                  [attr.aria-label]="clearAriaLabel"
                  [attr.aria-describedby]="resolvedId">
            ×
          </button>
        }
      </div>

      @if (hint && !showError()) {
        <div class="ngxsmk-tel__hint" [id]="resolvedId + '-hint'">{{ hint }}</div>
      }
      @if (showError() && errorText) {
        <div class="ngxsmk-tel__error" 
             [id]="resolvedId + '-error'"
             role="alert"
             [attr.aria-live]="'polite'">{{ errorText }}</div>
      }
      <div [id]="resolvedId + '-status'" 
           class="sr-only" 
           role="status" 
           [attr.aria-live]="'polite'"
           [attr.aria-atomic]="true">{{ getAriaStatusMessage() }}</div>
    </div>
  `, providers: [
                        { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NgxsmkTelInputComponent), multi: true },
                        { provide: NG_VALIDATORS, useExisting: forwardRef(() => NgxsmkTelInputComponent), multi: true }
                    ], styles: [":host{--tel-bg: #fff;--tel-fg: #0f172a;--tel-border: #c0c0c0;--tel-border-hover: #9aa0a6;--tel-ring: #2563eb;--tel-placeholder: #9ca3af;--tel-error: #ef4444;--tel-success: #10b981;--tel-warning: #f59e0b;--tel-radius: 8px;--tel-focus-shadow: 0 0 0 2px rgba(37, 99, 235, .2);--tel-dd-bg: #fff;--tel-dd-border: var(--tel-border);--tel-dd-shadow: 0 24px 60px rgba(0, 0, 0, .18);--tel-dd-radius: 8px;--tel-dd-item-hover: rgba(37, 99, 235, .08);--tel-dd-z: 2000;--tel-dd-search-bg: rgba(148, 163, 184, .08);display:block;contain:layout style;isolation:isolate}:host-context(.dark):not([data-theme=light]):not(.light),:host([data-theme=dark]),:host(.dark){--tel-bg: #0f172a;--tel-fg: #e2e8f0;--tel-border: #334155;--tel-border-hover: #475569;--tel-ring: #60a5fa;--tel-placeholder: #94a3b8;--tel-error: #f87171;--tel-success: #34d399;--tel-warning: #fbbf24;--tel-focus-shadow: 0 0 0 .2rem rgba(96, 165, 250, .25);--tel-dd-bg: #1e293b;--tel-dd-border: #334155;--tel-dd-shadow: 0 24px 60px rgba(0, 0, 0, .4);--tel-dd-search-bg: rgba(148, 163, 184, .12)}:host([data-theme=light]),:host(.light){--tel-bg: #fff !important;--tel-fg: #0f172a !important;--tel-border: #c0c0c0 !important;--tel-border-hover: #9aa0a6 !important;--tel-ring: #2563eb !important;--tel-placeholder: #9ca3af !important;--tel-error: #ef4444 !important;--tel-success: #10b981 !important;--tel-warning: #f59e0b !important;--tel-focus-shadow: 0 0 0 2px rgba(37, 99, 235, .2) !important;--tel-dd-bg: #fff !important;--tel-dd-border: #c0c0c0 !important;--tel-dd-shadow: 0 24px 60px rgba(0, 0, 0, .18) !important;--tel-dd-search-bg: rgba(148, 163, 184, .08) !important}:host-context(.dark):not([data-theme=light]):not(.light) ::ng-deep .iti__country-list,:host([data-theme=dark]) ::ng-deep .iti__country-list,:host(.dark) ::ng-deep .iti__country-list{background:var(--tel-dd-bg)!important;border-color:var(--tel-dd-border)!important;color:#e2e8f0!important}:host-context(.dark):not([data-theme=light]):not(.light) ::ng-deep .iti__search-input,:host([data-theme=dark]) ::ng-deep .iti__search-input,:host(.dark) ::ng-deep .iti__search-input{background:var(--tel-dd-search-bg)!important;color:#fff!important;border-bottom-color:var(--tel-dd-border)!important}:host-context(.dark):not([data-theme=light]):not(.light) ::ng-deep .iti__country,:host([data-theme=dark]) ::ng-deep .iti__country,:host(.dark) ::ng-deep .iti__country{color:#e2e8f0!important}:host-context(.dark):not([data-theme=light]):not(.light) ::ng-deep .iti__country.iti__highlight,:host([data-theme=dark]) ::ng-deep .iti__country.iti__highlight,:host(.dark) ::ng-deep .iti__country.iti__highlight{background-color:var(--tel-dd-item-hover)!important}:host-context(.dark):not([data-theme=light]):not(.light) ::ng-deep .iti__country-name,:host([data-theme=dark]) ::ng-deep .iti__country-name,:host(.dark) ::ng-deep .iti__country-name{color:#e2e8f0!important}:host-context(.dark):not([data-theme=light]):not(.light) ::ng-deep .iti__country-code,:host([data-theme=dark]) ::ng-deep .iti__country-code,:host(.dark) ::ng-deep .iti__country-code{color:#94a3b8!important}:host-context(.dark):not([data-theme=light]) ::ng-deep .iti__dial-code,:host([data-theme=dark]) ::ng-deep .iti__dial-code,:host(.dark) ::ng-deep .iti__dial-code{color:#94a3b8!important}:host-context(.dark):not([data-theme=light]):not(.light) ::ng-deep .iti__arrow,:host([data-theme=dark]) ::ng-deep .iti__arrow,:host(.dark) ::ng-deep .iti__arrow{border-top-color:#e2e8f0!important;opacity:1}:host-context(.dark):not([data-theme=light]):not(.light) ::ng-deep .iti__arrow.iti__arrow--up,:host([data-theme=dark]) ::ng-deep .iti__arrow.iti__arrow--up,:host(.dark) ::ng-deep .iti__arrow.iti__arrow--up{border-top-color:transparent!important;border-bottom-color:#e2e8f0!important}.ngxsmk-tel{width:100%;color:var(--tel-fg)}.ngxsmk-tel.disabled{opacity:.7;cursor:not-allowed}.ngxsmk-tel__label{display:inline-block;margin-bottom:8px;font-size:.875rem;font-weight:500;color:var(--tel-fg)}.ngxsmk-tel__wrap{position:relative}.ngxsmk-tel-input__wrapper,:host ::ng-deep .iti{width:100%}.ngxsmk-tel-input__control{width:100%;height:40px;font:inherit;color:var(--tel-fg);background:var(--tel-bg);border:1px solid var(--tel-border);-webkit-border-radius:var(--tel-radius);-moz-border-radius:var(--tel-radius);border-radius:var(--tel-radius);padding:10px 40px 10px 12px;outline:none;-webkit-transition:border-color .2s cubic-bezier(.4,0,.2,1),box-shadow .2s cubic-bezier(.4,0,.2,1),background .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1);-moz-transition:border-color .2s cubic-bezier(.4,0,.2,1),box-shadow .2s cubic-bezier(.4,0,.2,1),background .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1);-o-transition:border-color .2s cubic-bezier(.4,0,.2,1),box-shadow .2s cubic-bezier(.4,0,.2,1),background .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1);transition:border-color .2s cubic-bezier(.4,0,.2,1),box-shadow .2s cubic-bezier(.4,0,.2,1),background .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1);will-change:border-color,box-shadow,background,transform;-webkit-transform:translateZ(0);transform:translateZ(0);box-shadow:0 1px 3px #0000001a;font-size:16px;line-height:1.5;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.ngxsmk-tel-input__control::placeholder{color:var(--tel-placeholder)}.ngxsmk-tel-input__control:hover:not(:disabled):not(:focus){border-color:var(--tel-border-hover);box-shadow:0 2px 4px #00000014,0 1px 2px #0000000a;transform:translateY(-1px)}.ngxsmk-tel-input__control:focus{border-color:var(--tel-ring);box-shadow:var(--tel-focus-shadow),0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f;background:var(--tel-bg);color:var(--tel-fg);transform:translateY(0)}[data-size=sm] .ngxsmk-tel-input__control{height:34px;font-size:13px;padding:6px 36px 6px 10px;border-radius:6px}[data-size=sm] :host ::ng-deep .iti__country-list,[data-size=sm] :host ::ng-deep .iti__search-input,[data-size=sm] :host ::ng-deep .iti__country,[data-size=sm] :host ::ng-deep .iti__country-name,[data-size=sm] :host ::ng-deep .iti__country-code,[data-size=sm] :host ::ng-deep .iti__dial-code{font-size:13px}[data-size=lg] .ngxsmk-tel-input__control{height:46px;font-size:16px;padding:12px 44px 12px 14px;border-radius:10px}[data-size=lg] :host ::ng-deep .iti__country-list,[data-size=lg] :host ::ng-deep .iti__search-input,[data-size=lg] :host ::ng-deep .iti__country,[data-size=lg] :host ::ng-deep .iti__country-name,[data-size=lg] :host ::ng-deep .iti__country-code,[data-size=lg] :host ::ng-deep .iti__dial-code{font-size:16px}:host ::ng-deep .iti__country-list,:host ::ng-deep .iti__search-input,:host ::ng-deep .iti__country,:host ::ng-deep .iti__country-name,:host ::ng-deep .iti__country-code,:host ::ng-deep .iti__dial-code{font-size:15px}[data-variant=filled] .ngxsmk-tel-input__control{background:#94a3b814}[data-variant=underline] .ngxsmk-tel-input__control{border:0;border-bottom:2px solid var(--tel-border);border-radius:0;padding-left:0;padding-right:34px}[data-variant=underline] .ngxsmk-tel-input__control:focus{border-bottom-color:var(--tel-ring);box-shadow:none}:host ::ng-deep .iti__flag-container{border-top-left-radius:var(--tel-radius);border-bottom-left-radius:var(--tel-radius);border:1px solid var(--tel-border);border-right:none;background:var(--tel-bg)}:host ::ng-deep .iti__selected-flag{height:100%;padding:0 10px;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;outline:none!important;border:none!important;box-shadow:none!important}:host ::ng-deep .iti__selected-flag:focus,:host ::ng-deep .iti__selected-flag:active,:host ::ng-deep .iti__selected-flag:focus-visible{outline:none!important;border:none!important;box-shadow:none!important}:host ::ng-deep .iti__selected-country{z-index:1;position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:100%;background:none;border:0;margin:0;padding:0;font-family:inherit;font-size:inherit;color:inherit;border-radius:0;font-weight:inherit;line-height:inherit;text-decoration:none;outline:none!important}:host ::ng-deep .iti__selected-country:focus,:host ::ng-deep .iti__selected-country:active,:host ::ng-deep .iti__selected-country:focus-visible{outline:none!important}:host ::ng-deep .iti__country-list{background:var(--tel-dd-bg);border:1px solid var(--tel-dd-border);-webkit-border-radius:var(--tel-dd-radius);-moz-border-radius:var(--tel-dd-radius);border-radius:var(--tel-dd-radius);box-shadow:var(--tel-dd-shadow);max-height:360px;max-height:min(50vh,360px);overflow:auto;padding:6px 0;width:100%;min-width:0;box-sizing:border-box;z-index:var(--tel-dd-z);contain:layout style;isolation:isolate;will-change:transform;color:var(--tel-fg);display:block;animation:slideDown .2s cubic-bezier(.4,0,.2,1)}@keyframes slideDown{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}:host ::ng-deep .iti--container .iti__country-list{z-index:var(--tel-dd-z);width:100%;min-width:0;box-sizing:border-box}:host ::ng-deep .iti__search-input{position:-webkit-sticky;position:sticky;top:0;margin:0;padding:10px 36px 10px 12px;width:100%;border:0;border-bottom:1px solid var(--tel-dd-border);outline:none;background:var(--tel-dd-search-bg);color:var(--tel-fg);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:host ::ng-deep .iti__search-box,:host ::ng-deep .iti__country-list>div:first-child{position:relative}:host ::ng-deep .iti__search-clear{position:absolute;right:8px;top:50%;transform:translateY(-50%);background:transparent;border:0;cursor:pointer;font-size:18px;line-height:1;width:24px;height:24px;display:flex;align-items:center;justify-content:center;color:var(--tel-placeholder);padding:0;z-index:10;transition:color .2s ease;-webkit-tap-highlight-color:transparent}:host ::ng-deep .iti__search-clear:hover{color:var(--tel-fg)}:host ::ng-deep .iti__search-clear:active{opacity:.7}:host ::ng-deep .iti__search-input::placeholder{color:var(--tel-placeholder)}:host ::ng-deep .iti__country{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:10px 12px;cursor:pointer;color:var(--tel-fg);transition:background-color .15s cubic-bezier(.4,0,.2,1),transform .15s cubic-bezier(.4,0,.2,1)}@supports (display: grid){:host ::ng-deep .iti__country{display:grid;grid-template-columns:28px 1fr auto;align-items:center;column-gap:.5rem}}:host ::ng-deep .iti__country.iti__highlight{background-color:var(--tel-dd-item-hover);transform:scale(.99)}:host ::ng-deep .iti__dial-code{color:var(--tel-placeholder);font-weight:600;margin-left:10px}:host ::ng-deep .iti__country-name{color:var(--tel-fg)}:host ::ng-deep .iti__country-code{color:var(--tel-placeholder);font-weight:500}.ngxsmk-tel__clear{position:absolute;right:8px;top:50%;transform:translateY(-50%);border:0;background:transparent;font-size:18px;line-height:1;width:28px;height:28px;border-radius:50%;cursor:pointer;color:var(--tel-placeholder);transition:color .2s ease}.ngxsmk-tel__clear:hover{color:var(--tel-fg)}.ngxsmk-tel__hint{margin-top:8px;font-size:12px;color:var(--tel-placeholder)}.ngxsmk-tel__error{margin-top:8px;font-size:12px;color:var(--tel-error)}.ngxsmk-tel__wrap.has-error .ngxsmk-tel-input__control{border-color:var(--tel-error);box-shadow:0 0 0 3px #ef444426}.ngxsmk-tel.disabled .iti__flag-container,.ngxsmk-tel.disabled .iti__selected-flag{pointer-events:none;opacity:.6}:host-context(.dark):not([data-theme=light]) .ngxsmk-tel-input__control,:host([data-theme=dark]) .ngxsmk-tel-input__control{background:#0f172a!important;color:#e2e8f0!important;border-color:#334155!important;box-shadow:0 1px 3px #0000004d!important}:host-context(.dark):not([data-theme=light]) .ngxsmk-tel-input__control:focus,:host([data-theme=dark]) .ngxsmk-tel-input__control:focus{background:#0f172a!important;color:#e2e8f0!important;border-color:#60a5fa!important;box-shadow:0 0 0 .2rem #60a5fa40!important}:host-context(.dark):not([data-theme=light]) .ngxsmk-tel-input__control::placeholder,:host([data-theme=dark]) .ngxsmk-tel-input__control::placeholder{color:#94a3b8!important;opacity:1}:host-context(.dark):not([data-theme=light]) .ngxsmk-tel__label,:host([data-theme=dark]) .ngxsmk-tel__label{color:#e2e8f0!important}:host-context(.dark):not([data-theme=light]) .ngxsmk-tel__hint,:host([data-theme=dark]) .ngxsmk-tel__hint{color:#94a3b8!important;opacity:1}:host-context(.dark):not([data-theme=light]) .ngxsmk-tel__error,:host([data-theme=dark]) .ngxsmk-tel__error{color:#f87171!important}:host-context(.dark):not([data-theme=light]) .ngxsmk-tel__clear,:host([data-theme=dark]) .ngxsmk-tel__clear{color:#94a3b8!important;opacity:1}:host-context(.dark):not([data-theme=light]) .ngxsmk-tel__clear:hover,:host([data-theme=dark]) .ngxsmk-tel__clear:hover{color:#e2e8f0!important;opacity:1}:host-context(.dark):not([data-theme=light]) ::ng-deep .iti__search-input::placeholder,:host([data-theme=dark]) ::ng-deep .iti__search-input::placeholder{color:#94a3b8!important;opacity:1}:host-context(.dark):not([data-theme=light]) ::ng-deep .iti__search-clear,:host([data-theme=dark]) ::ng-deep .iti__search-clear{color:#94a3b8!important;opacity:1}:host-context(.dark):not([data-theme=light]) ::ng-deep .iti__search-clear:hover,:host([data-theme=dark]) ::ng-deep .iti__search-clear:hover{color:#e2e8f0!important;opacity:1}:host-context(.dark):not([data-theme=light]) ::ng-deep .iti__selected-dial-code,:host([data-theme=dark]) ::ng-deep .iti__selected-dial-code{color:#e2e8f0!important}:host-context(.dark):not([data-theme=light]) ::ng-deep .iti__selected-flag,:host([data-theme=dark]) ::ng-deep .iti__selected-flag{color:#e2e8f0!important}:host([data-theme=light]) .ngxsmk-tel-input__control{background:#fff!important;background-color:#fff!important;color:#0f172a!important;border-color:silver!important;box-shadow:0 1px 3px #0000001a!important}:host([data-theme=light]) .ngxsmk-tel-input__control:focus{background:#fff!important;color:#0f172a!important;border-color:#2563eb!important;box-shadow:0 0 0 3px #2563eb40!important}:host([data-theme=light]) .ngxsmk-tel-input__control::placeholder{color:#9ca3af!important;opacity:1}:host([data-theme=light]) .ngxsmk-tel__label{color:#0f172a!important}:host([data-theme=light]) .ngxsmk-tel__hint{color:#6b7280!important;opacity:1}:host([data-theme=light]) .ngxsmk-tel__error{color:#ef4444!important}:host([data-theme=light]) .ngxsmk-tel__clear{color:#6b7280!important;opacity:1}:host([data-theme=light]) .ngxsmk-tel__clear:hover{color:#0f172a!important;opacity:1}:host([data-theme=light]) ::ng-deep .iti__search-input{background:#94a3b814!important;color:#0f172a!important;border-bottom-color:silver!important}:host([data-theme=light]) ::ng-deep .iti__search-input::placeholder{color:#9ca3af!important;opacity:1}:host([data-theme=light]) ::ng-deep .iti__search-clear{color:#6b7280!important;opacity:1}:host([data-theme=light]) ::ng-deep .iti__search-clear:hover{color:#0f172a!important;opacity:1}:host([data-theme=light]) ::ng-deep .iti__selected-dial-code{color:#6b7280!important}:host([data-theme=light]) ::ng-deep .iti__selected-flag{color:#0f172a!important}:host([data-theme=light]) ::ng-deep .iti__arrow{border-top-color:#0f172a!important;opacity:1}:host([data-theme=light]) ::ng-deep .iti__arrow:hover{opacity:1}:host([data-theme=light]) ::ng-deep .iti--allow-dropdown .iti__arrow{border-top-color:#0f172a!important}:host([data-theme=light]) ::ng-deep .iti__country-list{background:#fff!important;border-color:silver!important;color:#0f172a!important}:host([data-theme=light]) ::ng-deep .iti__country{color:#0f172a!important}:host([data-theme=light]) ::ng-deep .iti__country-name{color:#0f172a!important}:host([data-theme=light]) ::ng-deep .iti__country-code{color:#6b7280!important}:host([data-theme=light]) ::ng-deep .iti__dial-code{color:#6b7280!important}:host([data-theme=light]) ::ng-deep .iti__flag-container{background:#fff!important;border-color:silver!important}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}@media (max-width: 768px){.ngxsmk-tel__wrap{position:relative;width:100%;max-width:100%;overflow:visible}:host{width:100%;max-width:100%;display:block}.ngxsmk-tel{width:100%;max-width:100%}.ngxsmk-tel-input__wrapper,:host ::ng-deep .iti{width:100%!important;max-width:100%!important;box-sizing:border-box}.ngxsmk-tel-input__control{font-size:16px!important;padding:12px 44px 12px 12px;min-height:44px;width:100%!important;max-width:100%!important;box-sizing:border-box}.ngxsmk-tel__clear{width:44px;height:44px;min-width:44px;min-height:44px;right:4px;padding:8px;display:flex;align-items:center;justify-content:center;font-size:18px}:host ::ng-deep .iti__selected-flag{min-width:44px;min-height:44px;padding:0 12px;touch-action:manipulation;font-size:14px}:host ::ng-deep .iti__flag-box{width:20px;height:15px}:host ::ng-deep .iti__country-list{width:100%!important;max-width:100%!important;min-width:0!important;max-height:400px;max-height:min(70vh,400px);-webkit-overflow-scrolling:touch;overflow-x:hidden;position:absolute!important;top:100%!important;left:0!important;right:0!important;transform:none!important;margin-top:4px!important;box-shadow:0 4px 12px #00000026!important;box-sizing:border-box}:host ::ng-deep .iti--container{position:relative!important;width:100%!important;max-width:100%!important;box-sizing:border-box}:host ::ng-deep .iti__dropdown{position:relative!important;width:100%!important;box-sizing:border-box}:host ::ng-deep .iti__country-list{width:100%!important;min-width:0!important;max-width:100%!important;box-sizing:border-box}:host ::ng-deep .iti__search-input{padding-right:36px!important}:host ::ng-deep .iti__search-clear{width:28px!important;height:28px!important;font-size:20px!important;right:6px!important}:host ::ng-deep .iti__country{min-height:48px;padding:12px 14px;font-size:15px;box-sizing:border-box;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}@supports (display: grid){:host ::ng-deep .iti__country{display:grid;grid-template-columns:28px 1fr auto;column-gap:.625rem}}:host ::ng-deep .iti__country-name{font-size:15px!important;line-height:1.4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host ::ng-deep .iti__country-code{font-size:13px!important;line-height:1.4}:host ::ng-deep .iti__dial-code{font-size:14px!important;line-height:1.4;margin-left:8px;white-space:nowrap}:host ::ng-deep .iti__search-input{font-size:16px!important;padding:12px 14px;min-height:44px;width:100%!important;box-sizing:border-box}.ngxsmk-tel__label{font-size:.9375rem;margin-bottom:8px;line-height:1.4}.ngxsmk-tel__hint,.ngxsmk-tel__error{font-size:.8125rem;margin-top:8px;line-height:1.4}[data-size=sm] .ngxsmk-tel-input__control{min-height:40px;font-size:16px!important;padding:10px 40px 10px 10px;width:100%!important;max-width:100%!important;box-sizing:border-box}[data-size=lg] .ngxsmk-tel-input__control{min-height:48px;font-size:16px!important;padding:14px 48px 14px 14px;width:100%!important;max-width:100%!important;box-sizing:border-box}[data-variant=underline] .ngxsmk-tel-input__control{padding-right:40px;min-height:44px;width:100%!important;max-width:100%!important;box-sizing:border-box}:host ::ng-deep .iti__flag-container{max-width:100%;overflow:hidden}:host ::ng-deep .iti__selected-dial-code{font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}}@media (max-width: 480px){:host{width:100%;max-width:100%}.ngxsmk-tel,.ngxsmk-tel__wrap{width:100%;max-width:100%}.ngxsmk-tel-input__wrapper,:host ::ng-deep .iti{width:100%!important;max-width:100%!important}.ngxsmk-tel-input__control{padding:10px 40px 10px 10px;font-size:16px!important;width:100%!important;max-width:100%!important;box-sizing:border-box}:host ::ng-deep .iti__selected-flag{padding:0 8px;min-width:40px;font-size:13px}:host ::ng-deep .iti__flag-box{width:18px;height:14px}:host ::ng-deep .iti__country-list{max-height:350px;max-height:min(60vh,350px);border-radius:8px;position:absolute!important;top:100%!important;left:0!important;right:0!important;transform:none!important;margin-top:4px!important;width:100%!important;max-width:100%!important;box-sizing:border-box}:host ::ng-deep .iti__search-input{padding-right:36px!important}:host ::ng-deep .iti__search-clear{width:24px!important;height:24px!important;font-size:18px!important;right:6px!important}:host ::ng-deep .iti__country{padding:10px 12px;min-height:44px;font-size:14px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}@supports (display: grid){:host ::ng-deep .iti__country{display:grid;grid-template-columns:26px 1fr auto;column-gap:.5rem}}:host ::ng-deep .iti__country-name{font-size:14px!important}:host ::ng-deep .iti__country-code{font-size:12px!important}:host ::ng-deep .iti__dial-code{font-size:13px!important;margin-left:6px}:host ::ng-deep .iti__search-input{font-size:16px!important;padding:10px 12px;min-height:44px}.ngxsmk-tel__clear{width:40px;height:40px;min-width:40px;min-height:40px;font-size:16px;right:2px}.ngxsmk-tel__label{font-size:.875rem;margin-bottom:6px;line-height:1.4}.ngxsmk-tel__hint,.ngxsmk-tel__error{font-size:.75rem;line-height:1.4}:host ::ng-deep .iti__flag-container{max-width:100%;overflow:hidden}:host ::ng-deep .iti__selected-dial-code{font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:60px}[data-size=sm] :host ::ng-deep .iti__country-name,[data-size=sm] :host ::ng-deep .iti__country-code,[data-size=sm] :host ::ng-deep .iti__dial-code{font-size:13px!important}[data-size=lg] :host ::ng-deep .iti__country-name,[data-size=lg] :host ::ng-deep .iti__country-code,[data-size=lg] :host ::ng-deep .iti__dial-code{font-size:15px!important}}@media (max-width: 768px) and (orientation: landscape){:host ::ng-deep .iti__country-list{max-height:300px;max-height:min(50vh,300px)}}@media (min-width: 481px) and (max-width: 1024px){.ngxsmk-tel-input__control{padding:11px 42px 11px 12px}:host ::ng-deep .iti__country-list{max-height:400px;max-height:min(60vh,400px)}}@media (hover: none) and (pointer: coarse){.ngxsmk-tel__clear{width:44px;height:44px;min-width:44px;min-height:44px}:host ::ng-deep .iti__selected-flag{min-width:44px;min-height:44px}:host ::ng-deep .iti__country{min-height:48px}:host ::ng-deep .iti__country:active{background-color:var(--tel-dd-item-hover)}.ngxsmk-tel__clear:active{background-color:#0000001a;transform:translateY(-50%) scale(.95)}}@media (-webkit-min-device-pixel-ratio: 2),(min-resolution: 192dpi){.ngxsmk-tel-input__control{border-width:.5px}}@media screen and (max-width: 768px){.ngxsmk-tel-input__control{-webkit-text-size-adjust:100%;text-size-adjust:100%}}@supports (padding: max(0px)){@media (max-width: 768px){:host ::ng-deep .iti__country-list{padding-left:max(6px,env(safe-area-inset-left));padding-right:max(6px,env(safe-area-inset-right))}}}\n"] }]
        }], ctorParameters: () => [{ type: i0.NgZone, decorators: [{
                    type: Optional
                }] }, { type: NgxsmkTelInputService }, { type: i0.ChangeDetectorRef }], propDecorators: { inputRef: [{
                type: ViewChild,
                args: ['telInput', { static: true }]
            }], initialCountry: [{
                type: Input
            }], preferredCountries: [{
                type: Input
            }], onlyCountries: [{
                type: Input
            }], separateDialCode: [{
                type: Input
            }], allowDropdown: [{
                type: Input
            }], nationalDisplay: [{
                type: Input
            }], formatWhenValid: [{
                type: Input
            }], placeholder: [{
                type: Input
            }], autocomplete: [{
                type: Input
            }], name: [{
                type: Input
            }], inputId: [{
                type: Input
            }], disabled: [{
                type: Input
            }], label: [{
                type: Input
            }], hint: [{
                type: Input
            }], errorText: [{
                type: Input
            }], size: [{
                type: Input
            }], variant: [{
                type: Input
            }], showClear: [{
                type: Input
            }], autoFocus: [{
                type: Input
            }], selectOnFocus: [{
                type: Input
            }], showErrorWhenTouched: [{
                type: Input
            }], dropdownAttachToBody: [{
                type: Input
            }], dropdownZIndex: [{
                type: Input
            }], i18n: [{
                type: Input,
                args: ['i18n']
            }], telI18n: [{
                type: Input,
                args: ['telI18n']
            }], localizedCountries: [{
                type: Input,
                args: ['localizedCountries']
            }], telLocalizedCountries: [{
                type: Input,
                args: ['telLocalizedCountries']
            }], clearAriaLabel: [{
                type: Input
            }], dir: [{
                type: Input
            }], autoPlaceholder: [{
                type: Input
            }], utilsScript: [{
                type: Input
            }], customPlaceholder: [{
                type: Input
            }], digitsOnly: [{
                type: Input
            }], lockWhenValid: [{
                type: Input
            }], theme: [{
                type: Input
            }], customColors: [{
                type: Input
            }], enableIntelligence: [{
                type: Input
            }], enableFormatSuggestions: [{
                type: Input
            }], countryChange: [{
                type: Output
            }], validityChange: [{
                type: Output
            }], inputChange: [{
                type: Output
            }], intelligenceChange: [{
                type: Output
            }], formatSuggestion: [{
                type: Output
            }] } });

class ThemeService {
    constructor() {
        this.platformId = inject(PLATFORM_ID);
        this.themeSubject = new BehaviorSubject('auto');
        this.currentThemeSubject = new BehaviorSubject('light');
        this.theme$ = this.themeSubject.asObservable();
        this.currentTheme$ = this.currentThemeSubject.asObservable();
        if (isPlatformBrowser(this.platformId)) {
            this.initializeTheme();
            this.setupSystemThemeListener();
        }
    }
    /** Get current theme preference */
    getTheme() {
        return this.themeSubject.value;
    }
    /** Get current resolved theme (light or dark) */
    getCurrentTheme() {
        return this.currentThemeSubject.value;
    }
    /** Set theme preference */
    setTheme(theme) {
        if (!isPlatformBrowser(this.platformId))
            return;
        this.themeSubject.next(theme);
        this.applyTheme(theme);
        this.saveThemePreference(theme);
    }
    /** Toggle between light and dark themes */
    toggleTheme() {
        const current = this.getCurrentTheme();
        this.setTheme(current === 'light' ? 'dark' : 'light');
    }
    /** Initialize theme from saved preference or system */
    initializeTheme() {
        const savedTheme = this.getSavedThemePreference();
        const theme = savedTheme || 'auto';
        this.setTheme(theme);
    }
    /** Apply theme to document and components */
    applyTheme(theme) {
        const resolvedTheme = this.resolveTheme(theme);
        this.currentThemeSubject.next(resolvedTheme);
        // Apply to document
        document.documentElement.setAttribute('data-theme', resolvedTheme);
        if (resolvedTheme === 'dark') {
            document.documentElement.classList.add('dark');
        }
        else {
            document.documentElement.classList.remove('dark');
        }
        // Update CSS custom properties
        this.updateCSSVariables(resolvedTheme);
        // Force update of all tel-input components
        this.updateTelInputComponents(resolvedTheme);
    }
    /** Update all tel-input components with the new theme */
    updateTelInputComponents(theme) {
        const telInputComponents = document.querySelectorAll('ngxsmk-tel-input');
        telInputComponents.forEach(component => {
            const element = component;
            element.setAttribute('data-theme', theme);
        });
    }
    /** Resolve theme to light or dark */
    resolveTheme(theme) {
        if (theme === 'auto') {
            return this.detectSystemTheme();
        }
        return theme;
    }
    /** Detect system theme preference */
    detectSystemTheme() {
        if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
            return 'dark';
        }
        return 'light';
    }
    /** Setup listener for system theme changes */
    setupSystemThemeListener() {
        if (window.matchMedia) {
            const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
            mediaQuery.addEventListener('change', () => {
                if (this.getTheme() === 'auto') {
                    this.applyTheme('auto');
                }
            });
        }
    }
    /** Update CSS custom properties for theme */
    updateCSSVariables(theme) {
        const root = document.documentElement;
        if (theme === 'dark') {
            root.style.setProperty('--tel-bg', '#212121');
            root.style.setProperty('--tel-fg', '#ffffff');
            root.style.setProperty('--tel-border', '#334155');
            root.style.setProperty('--tel-border-hover', '#475569');
            root.style.setProperty('--tel-ring', '#60a5fa');
            root.style.setProperty('--tel-placeholder', '#ffffff');
            root.style.setProperty('--tel-error', '#f87171');
            root.style.setProperty('--tel-success', '#34d399');
            root.style.setProperty('--tel-warning', '#fbbf24');
            root.style.setProperty('--tel-dd-bg', '#212121');
            root.style.setProperty('--tel-dd-border', '#324056');
            root.style.setProperty('--tel-dd-shadow', '0 24px 60px rgba(0, 0, 0, .4)');
            root.style.setProperty('--tel-dd-search-bg', 'rgba(148, 163, 184, .12)');
        }
        else {
            root.style.setProperty('--tel-bg', '#fff');
            root.style.setProperty('--tel-fg', '#0f172a');
            root.style.setProperty('--tel-border', '#c0c0c0');
            root.style.setProperty('--tel-border-hover', '#9aa0a6');
            root.style.setProperty('--tel-ring', '#2563eb');
            root.style.setProperty('--tel-placeholder', '#9ca3af');
            root.style.setProperty('--tel-error', '#ef4444');
            root.style.setProperty('--tel-success', '#10b981');
            root.style.setProperty('--tel-warning', '#f59e0b');
            root.style.setProperty('--tel-dd-bg', '#fff');
            root.style.setProperty('--tel-dd-border', '#c0c0c0');
            root.style.setProperty('--tel-dd-shadow', '0 24px 60px rgba(0, 0, 0, .18)');
            root.style.setProperty('--tel-dd-search-bg', 'rgba(148, 163, 184, .08)');
        }
    }
    /** Save theme preference to localStorage */
    saveThemePreference(theme) {
        try {
            localStorage.setItem('ngxsmk-tel-input-theme', theme);
        }
        catch (error) {
            console.warn('Failed to save theme preference:', error);
        }
    }
    /** Get saved theme preference from localStorage */
    getSavedThemePreference() {
        try {
            const saved = localStorage.getItem('ngxsmk-tel-input-theme');
            return saved;
        }
        catch (error) {
            console.warn('Failed to load theme preference:', error);
            return null;
        }
    }
    /** Check if dark theme is active */
    isDarkTheme() {
        return this.getCurrentTheme() === 'dark';
    }
    /** Check if light theme is active */
    isLightTheme() {
        return this.getCurrentTheme() === 'light';
    }
    /** Check if auto theme is set */
    isAutoTheme() {
        return this.getTheme() === 'auto';
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ThemeService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ThemeService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }], ctorParameters: () => [] });

/**
 * Utility functions for phone number input optimization and performance.
 * Provides helper methods for common operations like debouncing, throttling, and DOM manipulation.
 */
class PhoneInputUtils {
    /**
     * Converts any string to digits only (NSN - National Significant Number basis).
     * Removes all non-digit characters.
     *
     * @param v - Input string that may contain formatting characters
     * @returns String containing only digits
     *
     * @example
     * ```typescript
     * PhoneInputUtils.toNSN('(202) 555-1234'); // Returns '2025551234'
     * PhoneInputUtils.toNSN('+1 202-555-1234'); // Returns '12025551234'
     * ```
     */
    static toNSN(v) {
        return (v ?? '').replace(/\D/g, '');
    }
    /**
     * Strips exactly one leading trunk '0' from national input.
     * Used for countries like Sri Lanka where national format includes a leading 0.
     *
     * @param nsn - National Significant Number string
     * @returns NSN with leading zero removed (if present)
     *
     * @example
     * ```typescript
     * PhoneInputUtils.stripLeadingZero('0712345678'); // Returns '712345678'
     * PhoneInputUtils.stripLeadingZero('712345678'); // Returns '712345678'
     * ```
     */
    static stripLeadingZero(nsn) {
        return nsn.replace(/^0/, '');
    }
    /**
     * Creates a cache key for phone number operations.
     * Combines input and country code into a unique key string.
     *
     * @param input - Phone number input string
     * @param iso2 - ISO 3166-1 alpha-2 country code
     * @returns Cache key string in format "input|iso2"
     *
     * @example
     * ```typescript
     * PhoneInputUtils.createCacheKey('2025551234', 'US'); // Returns '2025551234|US'
     * ```
     */
    static createCacheKey(input, iso2) {
        return `${input || ''}|${iso2}`;
    }
    /**
     * Creates a debounced version of a function.
     * The debounced function delays execution until after wait milliseconds have elapsed
     * since the last time it was invoked.
     *
     * @param func - Function to debounce
     * @param wait - Number of milliseconds to wait
     * @returns Debounced function
     *
     * @example
     * ```typescript
     * const debouncedHandler = PhoneInputUtils.debounce((value: string) => {
     *   console.log(value);
     * }, 300);
     *
     * debouncedHandler('a'); // Waits 300ms
     * debouncedHandler('ab'); // Cancels previous, waits 300ms
     * debouncedHandler('abc'); // Cancels previous, waits 300ms, then logs 'abc'
     * ```
     */
    static debounce(func, wait) {
        let timeout = null;
        return (...args) => {
            if (timeout)
                clearTimeout(timeout);
            timeout = setTimeout(() => func.apply(this, args), wait);
        };
    }
    /**
     * Creates a throttled version of a function.
     * The throttled function will only execute once per limit milliseconds.
     *
     * @param func - Function to throttle
     * @param limit - Number of milliseconds between executions
     * @returns Throttled function
     *
     * @example
     * ```typescript
     * const throttledHandler = PhoneInputUtils.throttle((value: string) => {
     *   console.log(value);
     * }, 100);
     *
     * throttledHandler('a'); // Executes immediately
     * throttledHandler('b'); // Ignored (within 100ms)
     * throttledHandler('c'); // Ignored (within 100ms)
     * // After 100ms, next call will execute
     * ```
     */
    static throttle(func, limit) {
        let inThrottle;
        return (...args) => {
            if (!inThrottle) {
                func.apply(this, args);
                inThrottle = true;
                setTimeout(() => inThrottle = false, limit);
            }
        };
    }
    /**
     * Checks if a string contains only digits.
     *
     * @param str - String to check
     * @returns true if string contains only digits, false otherwise
     *
     * @example
     * ```typescript
     * PhoneInputUtils.isDigitsOnly('12345'); // Returns true
     * PhoneInputUtils.isDigitsOnly('123-45'); // Returns false
     * ```
     */
    static isDigitsOnly(str) {
        return /^\d+$/.test(str);
    }
    /**
     * Safely gets an element's value with fallback to empty string.
     *
     * @param element - HTML input element (may be null)
     * @returns Element value or empty string if element is null/undefined
     *
     * @example
     * ```typescript
     * const value = PhoneInputUtils.getElementValue(inputElement); // Returns value or ''
     * ```
     */
    static getElementValue(element) {
        return element?.value?.trim() || '';
    }
    /**
     * Checks if an element is currently visible in the viewport.
     * Useful for performance optimization (e.g., lazy loading).
     *
     * @param element - HTML element to check
     * @returns true if element is in viewport, false otherwise
     */
    static isInViewport(element) {
        const rect = element.getBoundingClientRect();
        return (rect.top >= 0 &&
            rect.left >= 0 &&
            rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
            rect.right <= (window.innerWidth || document.documentElement.clientWidth));
    }
    /**
     * Creates an optimized event listener with cleanup function.
     * Returns a function that removes the event listener when called.
     *
     * @param element - HTML element to attach listener to
     * @param event - Event name (e.g., 'click', 'input')
     * @param handler - Event handler function
     * @param options - Optional AddEventListenerOptions
     * @returns Cleanup function that removes the event listener
     *
     * @example
     * ```typescript
     * const cleanup = PhoneInputUtils.addEventListener(element, 'click', handler);
     * // Later...
     * cleanup(); // Removes the event listener
     * ```
     */
    static createEventListener(element, event, handler, options) {
        element.addEventListener(event, handler, options);
        return () => element.removeEventListener(event, handler, options);
    }
    /**
     * Batches DOM operations for better performance.
     * Executes all operations in a single requestAnimationFrame callback.
     *
     * @param operations - Array of functions that perform DOM operations
     *
     * @example
     * ```typescript
     * PhoneInputUtils.batchDOMOperations([
     *   () => element1.style.display = 'none',
     *   () => element2.classList.add('active'),
     *   () => element3.textContent = 'Updated'
     * ]);
     * ```
     */
    static batchDOMOperations(operations) {
        requestAnimationFrame(() => {
            operations.forEach(op => op());
        });
    }
}

/**
 * Angular Material theme configuration helper
 */
const MATERIAL_THEME_CONFIG = new InjectionToken('MATERIAL_THEME_CONFIG');
/**
 * Provides Material theme configuration
 */
function provideMaterialTheme(config = {}) {
    return {
        provide: MATERIAL_THEME_CONFIG,
        useValue: {
            primaryColor: '#3f51b5',
            accentColor: '#ff4081',
            warnColor: '#f44336',
            density: 'comfortable',
            ...config
        }
    };
}

/**
 * PrimeNG theme configuration helper
 */
const PRIMENG_THEME_CONFIG = new InjectionToken('PRIMENG_THEME_CONFIG');
/**
 * Provides PrimeNG theme configuration
 */
function providePrimeNGTheme(config = {}) {
    return {
        provide: PRIMENG_THEME_CONFIG,
        useValue: {
            theme: 'lara-light',
            ripple: true,
            inputStyle: 'outlined',
            ...config
        }
    };
}

/**
 * Mock phone service for testing
 */
/**
 * Mock implementation of NgxsmkTelInputService for testing
 */
class MockNgxsmkTelInputService extends NgxsmkTelInputService {
    constructor() {
        super(...arguments);
        this.mockValidNumbers = new Set();
        this.mockInvalidNumbers = new Set();
        this.mockParseResults = new Map();
        this.shouldThrowError = false;
        this.errorMessage = 'Mock error';
    }
    /**
     * Add a valid phone number for testing
     */
    addValidNumber(number, country = 'US') {
        this.mockValidNumbers.add(`${number}|${country}`);
    }
    /**
     * Add an invalid phone number for testing
     */
    addInvalidNumber(number, country = 'US') {
        this.mockInvalidNumbers.add(`${number}|${country}`);
    }
    /**
     * Set a custom parse result for a specific input
     */
    setParseResult(input, country, result) {
        const key = `${input}|${country}`;
        this.mockParseResults.set(key, result);
    }
    /**
     * Configure the service to throw an error
     */
    setShouldThrowError(shouldThrow, message = 'Mock error') {
        this.shouldThrowError = shouldThrow;
        this.errorMessage = message;
    }
    /**
     * Clear all mock data
     */
    clearMocks() {
        this.mockValidNumbers.clear();
        this.mockInvalidNumbers.clear();
        this.mockParseResults.clear();
        this.shouldThrowError = false;
        this.clearCache();
    }
    parse(input, iso2) {
        if (this.shouldThrowError) {
            throw new Error(this.errorMessage);
        }
        const key = `${input || ''}|${iso2}`;
        // Check for custom parse result
        if (this.mockParseResults.has(key)) {
            return this.mockParseResults.get(key);
        }
        // Check if it's a known valid/invalid number
        const isValid = this.mockValidNumbers.has(key);
        const isInvalid = this.mockInvalidNumbers.has(key);
        if (isValid) {
            return {
                e164: input.startsWith('+') ? input : `+1${input}`,
                national: input,
                isValid: true
            };
        }
        if (isInvalid) {
            return {
                e164: null,
                national: null,
                isValid: false
            };
        }
        // Fallback to parent implementation
        return super.parse(input, iso2);
    }
    isValid(input, iso2) {
        if (this.shouldThrowError) {
            throw new Error(this.errorMessage);
        }
        const key = `${input || ''}|${iso2}`;
        if (this.mockValidNumbers.has(key)) {
            return true;
        }
        if (this.mockInvalidNumbers.has(key)) {
            return false;
        }
        // Fallback to parent implementation
        return super.isValid(input, iso2);
    }
    parseWithInvalidDetection(input, iso2) {
        if (this.shouldThrowError) {
            throw new Error(this.errorMessage);
        }
        const parseResult = this.parse(input, iso2);
        return {
            ...parseResult,
            isInvalidInternational: !parseResult.isValid && input.length > 3
        };
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MockNgxsmkTelInputService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MockNgxsmkTelInputService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MockNgxsmkTelInputService, decorators: [{
            type: Injectable
        }] });

/**
 * Test fixtures for ngxsmk-tel-input
 */
/**
 * Test data fixtures
 */
const TEST_PHONE_NUMBERS = {
    valid: {
        US: '+12025551234',
        US_NATIONAL: '2025551234',
        GB: '+442071234567',
        GB_NATIONAL: '02071234567',
        AU: '+61234567890',
        AU_NATIONAL: '0234567890',
        CA: '+14165551234',
        CA_NATIONAL: '4165551234'
    },
    invalid: {
        TOO_SHORT: '123',
        TOO_LONG: '12345678901234567890',
        INVALID_COUNTRY_CODE: '1123456789',
        INVALID_FORMAT: 'abc123def'
    }
};
const TEST_COUNTRIES = ['US', 'GB', 'AU', 'CA', 'DE', 'FR', 'JP', 'CN'];
/**
 * Helper to create a test component fixture
 */
function createTestComponentFixture(fixture) {
    fixture.detectChanges();
    return fixture;
}
/**
 * Helper to get phone input component from fixture
 */
function getPhoneInputComponent(fixture) {
    const component = fixture.componentInstance;
    const phoneInput = component.phoneInput || component.telInput;
    if (!phoneInput) {
        throw new Error('Phone input component not found. Use ViewChild with reference name "phoneInput" or "telInput"');
    }
    return phoneInput;
}
/**
 * Helper to set phone input value
 */
function setPhoneInputValue(component, value) {
    component.writeValue(value);
}
/**
 * Helper to select country
 */
function selectCountry(component, country) {
    component.selectCountry(country);
}
/**
 * Helper to trigger input event
 */
function triggerInputEvent(fixture, value) {
    const input = fixture.nativeElement.querySelector('input[type="tel"]');
    if (input) {
        input.value = value;
        input.dispatchEvent(new Event('input'));
        fixture.detectChanges();
    }
}
/**
 * Helper to trigger blur event
 */
function triggerBlurEvent(fixture) {
    const input = fixture.nativeElement.querySelector('input[type="tel"]');
    if (input) {
        input.dispatchEvent(new Event('blur'));
        fixture.detectChanges();
    }
}
/**
 * Helper to trigger focus event
 */
function triggerFocusEvent(fixture) {
    const input = fixture.nativeElement.querySelector('input[type="tel"]');
    if (input) {
        input.dispatchEvent(new Event('focus'));
        fixture.detectChanges();
    }
}
/**
 * Helper to get current input value
 */
function getInputValue(fixture) {
    const input = fixture.nativeElement.querySelector('input[type="tel"]');
    return input ? input.value : '';
}
/**
 * Helper to check if input is valid
 */
function isInputValid(component) {
    return component.isValid();
}
/**
 * Helper to check if input has errors
 */
function hasInputErrors(component) {
    return component.hasErrors();
}
/**
 * Helper to get validation errors
 */
function getValidationErrors(component) {
    return component.validationStatus().errorKeys;
}
/**
 * Helper to wait for async operations
 */
function waitForAsync(fn) {
    return new Promise((resolve) => {
        setTimeout(() => {
            fn();
            resolve();
        }, 0);
    });
}
/**
 * Helper to create test form control
 */
function createTestFormControl(value = null) {
    const control = {
        value,
        setValue: function (val) {
            control.value = val;
        },
        patchValue: function (val) {
            control.value = val;
        },
        reset: function (val = null) {
            control.value = val;
        }
    };
    return control;
}
/**
 * Test scenarios
 */
const TEST_SCENARIOS = {
    validUSNumber: {
        input: TEST_PHONE_NUMBERS.valid.US_NATIONAL,
        country: 'US',
        expectedE164: TEST_PHONE_NUMBERS.valid.US,
        expectedValid: true
    },
    validUKNumber: {
        input: TEST_PHONE_NUMBERS.valid.GB_NATIONAL,
        country: 'GB',
        expectedE164: TEST_PHONE_NUMBERS.valid.GB,
        expectedValid: true
    },
    invalidNumber: {
        input: TEST_PHONE_NUMBERS.invalid.TOO_SHORT,
        country: 'US',
        expectedE164: null,
        expectedValid: false
    },
    invalidCountryCode: {
        input: TEST_PHONE_NUMBERS.invalid.INVALID_COUNTRY_CODE,
        country: 'US',
        expectedE164: null,
        expectedValid: false,
        expectedError: 'phoneInvalidCountryCode'
    }
};

/**
 * E2E testing helpers for ngxsmk-tel-input
 */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const by = { css: (selector) => ({ selector }) };
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const element = (selector) => selector;
/**
 * E2E selectors
 */
const E2E_SELECTORS = {
    phoneInput: 'ngxsmk-tel-input input[type="tel"]',
    phoneInputWrapper: 'ngxsmk-tel-input',
    countryDropdown: '.iti__selected-flag',
    countryList: '.iti__country-list',
    clearButton: '.ngxsmk-tel__clear',
    errorMessage: '.ngxsmk-tel__error',
    hint: '.ngxsmk-tel__hint',
    label: '.ngxsmk-tel__label'
};
/**
 * Get phone input element
 */
function getPhoneInput() {
    return element(by.css(E2E_SELECTORS.phoneInput));
}
/**
 * Get phone input wrapper
 */
function getPhoneInputWrapper() {
    return element(by.css(E2E_SELECTORS.phoneInputWrapper));
}
/**
 * Type phone number
 */
async function typePhoneNumber(value) {
    const input = getPhoneInput();
    await input.clear();
    await input.sendKeys(value);
}
/**
 * Clear phone input
 */
async function clearPhoneInput() {
    const input = getPhoneInput();
    await input.clear();
}
/**
 * Get phone input value
 */
async function getPhoneInputValue() {
    const input = getPhoneInput();
    return await input.getAttribute('value');
}
/**
 * Click country dropdown
 */
async function clickCountryDropdown() {
    const dropdown = element(by.css(E2E_SELECTORS.countryDropdown));
    await dropdown.click();
}
/**
 * Select country from dropdown
 */
async function selectCountryFromDropdown(countryCode) {
    await clickCountryDropdown();
    const countryItem = element(by.css(`.iti__country[data-country-code="${countryCode.toLowerCase()}"]`));
    await countryItem.click();
}
/**
 * Click clear button
 */
async function clickClearButton() {
    const clearBtn = element(by.css(E2E_SELECTORS.clearButton));
    if (await clearBtn.isPresent()) {
        await clearBtn.click();
    }
}
/**
 * Get error message
 */
async function getErrorMessage() {
    const errorEl = element(by.css(E2E_SELECTORS.errorMessage));
    if (await errorEl.isPresent()) {
        return await errorEl.getText();
    }
    return '';
}
/**
 * Check if error is displayed
 */
async function isErrorDisplayed() {
    const errorEl = element(by.css(E2E_SELECTORS.errorMessage));
    return await errorEl.isPresent();
}
/**
 * Get hint text
 */
async function getHintText() {
    const hintEl = element(by.css(E2E_SELECTORS.hint));
    if (await hintEl.isPresent()) {
        return await hintEl.getText();
    }
    return '';
}
/**
 * Get label text
 */
async function getLabelText() {
    const labelEl = element(by.css(E2E_SELECTORS.label));
    if (await labelEl.isPresent()) {
        return await labelEl.getText();
    }
    return '';
}
/**
 * Check if input is disabled
 */
async function isInputDisabled() {
    const input = getPhoneInput();
    return await input.getAttribute('disabled').then((value) => value !== null, () => false);
}
/**
 * Focus phone input
 */
async function focusPhoneInput() {
    const input = getPhoneInput();
    await input.click();
}
/**
 * Blur phone input
 */
async function blurPhoneInput() {
    // Click outside the input
    const body = element(by.tagName('body'));
    await body.click();
}
/**
 * Wait for validation
 */
async function waitForValidation(timeout = 1000) {
    await new Promise(resolve => setTimeout(resolve, timeout));
}
/**
 * Check if country dropdown is open
 */
async function isCountryDropdownOpen() {
    const countryList = element(by.css(E2E_SELECTORS.countryList));
    return await countryList.isPresent() && await countryList.isDisplayed();
}
/**
 * Search for country in dropdown
 */
async function searchCountryInDropdown(searchTerm) {
    await clickCountryDropdown();
    const searchInput = element(by.css('.iti__search-input'));
    if (await searchInput.isPresent()) {
        await searchInput.clear();
        await searchInput.sendKeys(searchTerm);
    }
}
/**
 * Get selected country code
 */
async function getSelectedCountryCode() {
    const flag = element(by.css(E2E_SELECTORS.countryDropdown));
    if (await flag.isPresent()) {
        const countryCode = await flag.getAttribute('data-country-code');
        return countryCode ? countryCode.toUpperCase() : '';
    }
    return '';
}
/**
 * E2E test scenarios
 */
const E2E_SCENARIOS = {
    /**
     * Test valid phone number input
     */
    async testValidPhoneInput(phoneNumber, countryCode = 'US') {
        await selectCountryFromDropdown(countryCode);
        await typePhoneNumber(phoneNumber);
        await waitForValidation();
        const errorDisplayed = await isErrorDisplayed();
        if (errorDisplayed) {
            throw new Error(`Expected valid input but error was displayed: ${await getErrorMessage()}`);
        }
    },
    /**
     * Test invalid phone number input
     */
    async testInvalidPhoneInput(phoneNumber, countryCode = 'US') {
        await selectCountryFromDropdown(countryCode);
        await typePhoneNumber(phoneNumber);
        await waitForValidation();
        const errorDisplayed = await isErrorDisplayed();
        if (!errorDisplayed) {
            throw new Error('Expected error to be displayed for invalid input');
        }
    },
    /**
     * Test country selection
     */
    async testCountrySelection(countryCode) {
        await selectCountryFromDropdown(countryCode);
        await waitForValidation();
        const selectedCode = await getSelectedCountryCode();
        if (selectedCode !== countryCode.toUpperCase()) {
            throw new Error(`Expected country ${countryCode} but got ${selectedCode}`);
        }
    },
    /**
     * Test clear button
     */
    async testClearButton() {
        await typePhoneNumber('1234567890');
        await clickClearButton();
        await waitForValidation();
        const value = await getPhoneInputValue();
        if (value !== '') {
            throw new Error(`Expected empty value after clear but got: ${value}`);
        }
    }
};

/**
 * Testing module for ngxsmk-tel-input
 */
/**
 * Testing module that provides mock services
 * Note: NgxsmkTelInputComponent is standalone and should be imported directly in test components
 */
class NgxsmkTelInputTestingModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgxsmkTelInputTestingModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: NgxsmkTelInputTestingModule }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgxsmkTelInputTestingModule, providers: [
            {
                provide: NgxsmkTelInputService,
                useClass: MockNgxsmkTelInputService
            }
        ] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgxsmkTelInputTestingModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [],
                    imports: [],
                    exports: [],
                    providers: [
                        {
                            provide: NgxsmkTelInputService,
                            useClass: MockNgxsmkTelInputService
                        }
                    ]
                }]
        }] });

/**
 * Base verification service interface
 */
class VerificationService {
}

/**
 * Twilio verification service integration
 */
const TWILIO_CONFIG = 'TWILIO_CONFIG';
class TwilioVerificationService extends VerificationService {
    constructor(http, config) {
        super();
        this.http = http;
        this.apiUrl = 'https://verify.twilio.com/v2/Services';
        this.config = null;
        this.config = config || null;
    }
    setConfig(config) {
        this.config = config;
    }
    verify(request) {
        if (!this.config) {
            throw new Error('Twilio configuration not provided');
        }
        const serviceSid = this.config.serviceSid;
        if (!serviceSid) {
            throw new Error('Twilio Service SID not configured');
        }
        const url = `${this.apiUrl}/${serviceSid}/Verifications`;
        const headers = this.getAuthHeaders();
        const body = {
            To: request.phoneNumber,
            Channel: request.method === 'whatsapp' ? 'whatsapp' : request.method
        };
        return this.http.post(url, body, { headers }).pipe(map(response => ({
            success: true,
            sid: response.sid,
            expiresAt: new Date(Date.now() + 600000) // 10 minutes default
        })), catchError(error => {
            return from([{
                    success: false,
                    error: error.error?.message || 'Verification failed'
                }]);
        }));
    }
    check(request) {
        if (!this.config) {
            throw new Error('Twilio configuration not provided');
        }
        const serviceSid = this.config.serviceSid;
        if (!serviceSid) {
            throw new Error('Twilio Service SID not configured');
        }
        const url = `${this.apiUrl}/${serviceSid}/VerificationCheck`;
        const headers = this.getAuthHeaders();
        const body = {
            To: request.code,
            Code: request.code
        };
        return this.http.post(url, body, { headers }).pipe(map(response => ({
            success: true,
            verified: response.status === 'approved'
        })), catchError(error => {
            return from([{
                    success: false,
                    verified: false,
                    error: error.error?.message || 'Verification check failed'
                }]);
        }));
    }
    getAuthHeaders() {
        if (!this.config) {
            throw new Error('Twilio configuration not provided');
        }
        const auth = btoa(`${this.config.accountSid}:${this.config.authToken}`);
        return new HttpHeaders({
            'Authorization': `Basic ${auth}`,
            'Content-Type': 'application/x-www-form-urlencoded'
        });
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TwilioVerificationService, deps: [{ token: i1.HttpClient }, { token: TWILIO_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TwilioVerificationService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TwilioVerificationService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }], ctorParameters: () => [{ type: i1.HttpClient }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [TWILIO_CONFIG]
                }] }] });
/**
 * Provide Twilio verification service
 */
function provideTwilioVerification(config) {
    return [
        TwilioVerificationService,
        {
            provide: TWILIO_CONFIG,
            useValue: config
        }
    ];
}

/**
 * Vonage (Nexmo) verification service integration
 */
const VONAGE_CONFIG = 'VONAGE_CONFIG';
class VonageVerificationService extends VerificationService {
    constructor(http, config) {
        super();
        this.http = http;
        this.apiUrl = 'https://api.nexmo.com/verify';
        this.config = null;
        this.config = config || null;
    }
    setConfig(config) {
        this.config = config;
    }
    verify(request) {
        if (!this.config) {
            throw new Error('Vonage configuration not provided');
        }
        const url = `${this.apiUrl}/json`;
        const body = new URLSearchParams({
            api_key: this.config.apiKey,
            api_secret: this.config.apiSecret,
            number: request.phoneNumber,
            brand: this.config.brand || 'App',
            workflow_id: request.method === 'voice' ? '6' : '1'
        });
        const headers = new HttpHeaders({
            'Content-Type': 'application/x-www-form-urlencoded'
        });
        return this.http.post(url, body.toString(), { headers }).pipe(map(response => {
            if (response.status === '0') {
                return {
                    success: true,
                    sid: response.request_id,
                    expiresAt: new Date(Date.now() + 300000) // 5 minutes default
                };
            }
            else {
                return {
                    success: false,
                    error: response.error_text || 'Verification failed'
                };
            }
        }), catchError(error => {
            return from([{
                    success: false,
                    error: error.error?.message || 'Verification failed'
                }]);
        }));
    }
    check(request) {
        if (!this.config) {
            throw new Error('Vonage configuration not provided');
        }
        const url = `${this.apiUrl}/check/json`;
        const body = new URLSearchParams({
            api_key: this.config.apiKey,
            api_secret: this.config.apiSecret,
            request_id: request.sid,
            code: request.code
        });
        const headers = new HttpHeaders({
            'Content-Type': 'application/x-www-form-urlencoded'
        });
        return this.http.post(url, body.toString(), { headers }).pipe(map(response => {
            if (response.status === '0') {
                return {
                    success: true,
                    verified: true
                };
            }
            else {
                return {
                    success: false,
                    verified: false,
                    error: response.error_text || 'Verification check failed'
                };
            }
        }), catchError(error => {
            return from([{
                    success: false,
                    verified: false,
                    error: error.error?.message || 'Verification check failed'
                }]);
        }));
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VonageVerificationService, deps: [{ token: i1.HttpClient }, { token: VONAGE_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VonageVerificationService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: VonageVerificationService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }], ctorParameters: () => [{ type: i1.HttpClient }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [VONAGE_CONFIG]
                }] }] });
/**
 * Provide Vonage verification service
 */
function provideVonageVerification(config) {
    return [
        VonageVerificationService,
        {
            provide: VONAGE_CONFIG,
            useValue: config
        }
    ];
}

/**
 * AWS SNS verification service integration
 */
const AWS_SNS_CONFIG = 'AWS_SNS_CONFIG';
class AwsSnsVerificationService extends VerificationService {
    constructor(http, config) {
        super();
        this.http = http;
        this.config = null;
        this.config = config || null;
    }
    setConfig(config) {
        this.config = config;
    }
    verify(request) {
        if (!this.config) {
            throw new Error('AWS SNS configuration not provided');
        }
        // Generate OTP code (6 digits)
        const code = Math.floor(100000 + Math.random() * 900000).toString();
        // In a real implementation, you would:
        // 1. Store the code in a database/cache with the phone number
        // 2. Send SMS via AWS SNS
        // 3. Return the verification ID
        // For now, we'll simulate the API call
        const message = `Your verification code is: ${code}`;
        // Note: Actual AWS SNS integration requires AWS SDK and proper authentication
        // This is a simplified example
        return from(this.sendSmsViaSns(request.phoneNumber, message)).pipe(map(() => ({
            success: true,
            sid: `aws-sns-${Date.now()}`,
            expiresAt: new Date(Date.now() + 600000) // 10 minutes
        })), catchError(error => {
            return from([{
                    success: false,
                    error: error.message || 'SMS sending failed'
                }]);
        }));
    }
    check(request) {
        // In a real implementation, you would:
        // 1. Retrieve the stored code for the verification ID
        // 2. Compare with the provided code
        // 3. Return verification result
        // This is a simplified example
        return from([{
                success: true,
                verified: true // In real implementation, check against stored code
            }]);
    }
    async sendSmsViaSns(phoneNumber, message) {
        // Actual AWS SNS implementation would use AWS SDK
        // This is a placeholder
        if (!this.config) {
            throw new Error('AWS SNS configuration not provided');
        }
        // Example AWS SNS API call (simplified)
        // const sns = new AWS.SNS({
        //   accessKeyId: this.config.accessKeyId,
        //   secretAccessKey: this.config.secretAccessKey,
        //   region: this.config.region
        // });
        // 
        // await sns.publish({
        //   PhoneNumber: phoneNumber,
        //   Message: message
        // }).promise();
        // For now, just simulate success
        return Promise.resolve();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AwsSnsVerificationService, deps: [{ token: i1.HttpClient }, { token: AWS_SNS_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AwsSnsVerificationService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AwsSnsVerificationService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }], ctorParameters: () => [{ type: i1.HttpClient }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [AWS_SNS_CONFIG]
                }] }] });
/**
 * Provide AWS SNS verification service
 */
function provideAwsSnsVerification(config) {
    return [
        AwsSnsVerificationService,
        {
            provide: AWS_SNS_CONFIG,
            useValue: config
        }
    ];
}

/**
 * Enhanced TypeScript types and type guards for ngxsmk-tel-input
 */
/**
 * Type guard to check if a value is a valid CountryCode
 */
function isCountryCode(value) {
    if (typeof value !== 'string') {
        return false;
    }
    // Basic validation - ISO 3166-1 alpha-2 codes are 2 uppercase letters
    return /^[A-Z]{2}$/.test(value);
}
/**
 * Type guard to check if a value is a valid phone number string
 */
function isPhoneNumberString(value) {
    if (typeof value !== 'string') {
        return false;
    }
    // Basic validation - contains digits and optionally + or spaces/dashes
    return /^[\d\s\-+()]+$/.test(value) && value.replace(/\D/g, '').length >= 3;
}
/**
 * Type guard to check if ParseResult is valid
 */
function isValidParseResult(result) {
    return result.isValid === true && result.e164 !== null;
}
/**
 * Type guard to check if value is E.164 format
 */
function isE164Format(value) {
    if (typeof value !== 'string') {
        return false;
    }
    // E.164 format: + followed by 1-15 digits
    return /^\+[1-9]\d{1,14}$/.test(value);
}
/**
 * Type guard to check if CarrierInfo is complete
 */
function isCompleteCarrierInfo(info) {
    return info !== null && info.type !== 'UNKNOWN';
}
/**
 * Type guard to check if FormatSuggestion has high confidence
 */
function isHighConfidenceSuggestion(suggestion) {
    return suggestion !== null && suggestion.confidence >= 0.7;
}
/**
 * Create a branded E.164 phone number
 */
function createE164PhoneNumber(value) {
    if (isE164Format(value)) {
        return value;
    }
    return null;
}
/**
 * Create a branded national phone number
 */
function createNationalPhoneNumber(value, country) {
    if (isPhoneNumberString(value)) {
        return value;
    }
    return null;
}
/**
 * Create a typed validation result
 */
function createTypedValidationResult(parseResult, country) {
    const errors = [];
    if (!parseResult.isValid) {
        if (parseResult.e164 === null) {
            errors.push({
                code: 'INVALID',
                message: 'Invalid phone number format'
            });
        }
    }
    return {
        isValid: parseResult.isValid,
        e164: parseResult.e164 ? parseResult.e164 : null,
        national: parseResult.national ? parseResult.national : null,
        country,
        errors: errors
    };
}
/**
 * Assert that a value is a CountryCode (throws if not)
 */
function assertCountryCode(value) {
    if (!isCountryCode(value)) {
        throw new TypeError(`Expected CountryCode, got ${typeof value}: ${value}`);
    }
}
/**
 * Assert that a value is E.164 format (throws if not)
 */
function assertE164Format(value) {
    if (!isE164Format(value)) {
        throw new TypeError(`Expected E.164 format phone number, got: ${value}`);
    }
}

/**
 * Generated bundle index. Do not edit.
 */

export { AwsSnsVerificationService, E2E_SCENARIOS, E2E_SELECTORS, MATERIAL_THEME_CONFIG, MockNgxsmkTelInputService, NgxsmkTelInputComponent, NgxsmkTelInputService, NgxsmkTelInputTestingModule, PRIMENG_THEME_CONFIG, PhoneInputUtils, PhoneIntelligenceService, TEST_COUNTRIES, TEST_PHONE_NUMBERS, TEST_SCENARIOS, ThemeService, TwilioVerificationService, VerificationService, VonageVerificationService, assertCountryCode, assertE164Format, clearPhoneInput, clickClearButton, clickCountryDropdown, createE164PhoneNumber, createFormattedValueSignal, createNationalPhoneNumber, createPhoneInputState, createPhoneMetadataSignal, createTestComponentFixture, createTypedValidationResult, createValidationStatusSignal, getErrorMessage, getInputValue, getPhoneInput, getPhoneInputComponent, getPhoneInputValue, getValidationErrors, hasInputErrors, isCompleteCarrierInfo, isCountryCode, isE164Format, isErrorDisplayed, isHighConfidenceSuggestion, isInputValid, isPhoneNumberString, isValidParseResult, provideAwsSnsVerification, provideMaterialTheme, providePrimeNGTheme, provideTwilioVerification, provideVonageVerification, selectCountry, selectCountryFromDropdown, setPhoneInputValue, triggerBlurEvent, triggerFocusEvent, triggerInputEvent, typePhoneNumber };
//# sourceMappingURL=ngxsmk-tel-input.mjs.map