ngxsmk-tel-input 1.1.1 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ngxsmk-tel-input",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "Angular international telephone input with country flag dropdown, formatting & validation (intl-tel-input + libphonenumber). ControlValueAccessor. Supports Angular 17–19.",
5
5
  "keywords": [
6
6
  "ngxsmk-tel-input",
@@ -0,0 +1,220 @@
1
+ /* ---------- Theme tokens ---------- */
2
+ :host {
3
+ --tel-bg: #fff;
4
+ --tel-fg: #0f172a;
5
+ --tel-border: #c0c0c0;
6
+ --tel-border-hover: #9aa0a6;
7
+ --tel-ring: #2563eb;
8
+ --tel-placeholder: #9ca3af;
9
+ --tel-error: #ef4444;
10
+ --tel-radius: 12px;
11
+ --tel-focus-shadow: 0 0 0 3px rgba(37, 99, 235, .25);
12
+
13
+ --tel-dd-bg: var(--tel-bg);
14
+ --tel-dd-border: var(--tel-border);
15
+ --tel-dd-shadow: 0 24px 60px rgba(0, 0, 0, .18);
16
+ --tel-dd-radius: 12px;
17
+ --tel-dd-item-hover: rgba(37, 99, 235, .08);
18
+ --tel-dd-z: 2000;
19
+ --tel-dd-search-bg: rgba(148, 163, 184, .08);
20
+
21
+ display: block;
22
+ }
23
+
24
+ :host-context(.dark) {
25
+ --tel-bg: #0b0f17;
26
+ --tel-fg: #e5e7eb;
27
+ --tel-border: #334155;
28
+ --tel-border-hover: #475569;
29
+ --tel-ring: #60a5fa;
30
+ --tel-placeholder: #94a3b8;
31
+
32
+ --tel-dd-bg: #0f1521;
33
+ --tel-dd-border: #324056;
34
+ --tel-dd-search-bg: rgba(148, 163, 184, .12);
35
+ }
36
+
37
+ /* ---------- Structure ---------- */
38
+ .ngxsmk-tel {
39
+ width: 100%;
40
+ color: var(--tel-fg);
41
+ }
42
+
43
+ .ngxsmk-tel.disabled {
44
+ opacity: .7;
45
+ cursor: not-allowed;
46
+ }
47
+
48
+ .ngxsmk-tel__label {
49
+ display: inline-block;
50
+ margin-bottom: 6px;
51
+ font-size: .875rem;
52
+ font-weight: 500;
53
+ }
54
+
55
+ .ngxsmk-tel__wrap {
56
+ position: relative;
57
+ }
58
+
59
+ .ngxsmk-tel-input__wrapper,
60
+ :host ::ng-deep .iti {
61
+ width: 100%;
62
+ }
63
+
64
+ .ngxsmk-tel-input__control {
65
+ width: 100%;
66
+ height: 40px;
67
+ font: inherit;
68
+ color: var(--tel-fg);
69
+ background: var(--tel-bg);
70
+ border: 1px solid var(--tel-border);
71
+ border-radius: var(--tel-radius);
72
+ padding: 10px 40px 10px 12px;
73
+ outline: none;
74
+ transition: border-color .15s, box-shadow .15s, background .15s;
75
+ }
76
+
77
+ .ngxsmk-tel-input__control::placeholder {
78
+ color: var(--tel-placeholder);
79
+ }
80
+
81
+ .ngxsmk-tel-input__control:hover {
82
+ border-color: var(--tel-border-hover);
83
+ }
84
+
85
+ .ngxsmk-tel-input__control:focus {
86
+ border-color: var(--tel-ring);
87
+ box-shadow: var(--tel-focus-shadow);
88
+ }
89
+
90
+ /* Size presets */
91
+ [data-size="sm"] .ngxsmk-tel-input__control {
92
+ height: 34px;
93
+ font-size: 13px;
94
+ padding: 6px 36px 6px 10px;
95
+ border-radius: 10px;
96
+ }
97
+
98
+ [data-size="lg"] .ngxsmk-tel-input__control {
99
+ height: 46px;
100
+ font-size: 16px;
101
+ padding: 12px 44px 12px 14px;
102
+ border-radius: 14px;
103
+ }
104
+
105
+ /* Variants */
106
+ [data-variant="filled"] .ngxsmk-tel-input__control {
107
+ background: rgba(148, 163, 184, .08);
108
+ }
109
+
110
+ [data-variant="underline"] .ngxsmk-tel-input__control {
111
+ border: 0;
112
+ border-bottom: 2px solid var(--tel-border);
113
+ border-radius: 0;
114
+ padding-left: 0;
115
+ padding-right: 34px;
116
+ }
117
+
118
+ [data-variant="underline"] .ngxsmk-tel-input__control:focus {
119
+ border-bottom-color: var(--tel-ring);
120
+ box-shadow: none;
121
+ }
122
+
123
+ /* ---------- intl-tel-input dropdown (deep selectors) ---------- */
124
+ :host ::ng-deep .iti__flag-container {
125
+ border-top-left-radius: var(--tel-radius);
126
+ border-bottom-left-radius: var(--tel-radius);
127
+ border: 1px solid var(--tel-border);
128
+ border-right: none;
129
+ background: var(--tel-bg);
130
+ }
131
+
132
+ :host ::ng-deep .iti__selected-flag {
133
+ height: 100%;
134
+ padding: 0 10px;
135
+ display: inline-flex;
136
+ align-items: center;
137
+ }
138
+
139
+ :host ::ng-deep .iti__country-list {
140
+ background: var(--tel-dd-bg);
141
+ border: 1px solid var(--tel-dd-border);
142
+ border-radius: var(--tel-dd-radius);
143
+ box-shadow: var(--tel-dd-shadow);
144
+ max-height: min(50vh, 360px);
145
+ overflow: auto;
146
+ padding: 6px 0;
147
+ width: max(280px, 100%);
148
+ z-index: var(--tel-dd-z);
149
+ }
150
+
151
+ :host ::ng-deep .iti--container .iti__country-list {
152
+ z-index: var(--tel-dd-z);
153
+ }
154
+
155
+ :host ::ng-deep .iti__search-input {
156
+ position: sticky;
157
+ top: 0;
158
+ margin: 0;
159
+ padding: 10px 12px;
160
+ width: 100%;
161
+ border: 0;
162
+ border-bottom: 1px solid var(--tel-dd-border);
163
+ outline: none;
164
+ background: var(--tel-dd-search-bg);
165
+ color: var(--tel-fg);
166
+ }
167
+
168
+ :host ::ng-deep .iti__country {
169
+ display: grid;
170
+ grid-template-columns: 28px 1fr auto;
171
+ align-items: center;
172
+ column-gap: .5rem;
173
+ padding: 10px 12px;
174
+ cursor: pointer;
175
+ }
176
+
177
+ :host ::ng-deep .iti__dial-code {
178
+ color: var(--tel-placeholder);
179
+ font-weight: 600;
180
+ margin-left: 10px;
181
+ }
182
+
183
+ /* Clear button */
184
+ .ngxsmk-tel__clear {
185
+ position: absolute;
186
+ right: 8px;
187
+ top: 50%;
188
+ transform: translateY(-50%);
189
+ border: 0;
190
+ background: transparent;
191
+ font-size: 18px;
192
+ line-height: 1;
193
+ width: 28px;
194
+ height: 28px;
195
+ border-radius: 50%;
196
+ cursor: pointer;
197
+ color: var(--tel-placeholder);
198
+ }
199
+
200
+ .ngxsmk-tel__clear:hover {
201
+ background: rgba(148, 163, 184, .15);
202
+ }
203
+
204
+ /* Hint & Error */
205
+ .ngxsmk-tel__hint {
206
+ margin-top: 6px;
207
+ font-size: 12px;
208
+ color: var(--tel-placeholder);
209
+ }
210
+
211
+ .ngxsmk-tel__error {
212
+ margin-top: 6px;
213
+ font-size: 12px;
214
+ color: var(--tel-error);
215
+ }
216
+
217
+ .ngxsmk-tel__wrap.has-error .ngxsmk-tel-input__control {
218
+ border-color: var(--tel-error);
219
+ box-shadow: 0 0 0 3px rgba(239, 68, 68, .15);
220
+ }
@@ -89,260 +89,45 @@ export interface IntlTelI18n {
89
89
  }
90
90
  </div>
91
91
  `,
92
+ styleUrls: ['./ngxsmk-tel-input.component.scss'],
92
93
  providers: [
93
94
  {provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NgxsmkTelInputComponent), multi: true},
94
95
  {provide: NG_VALIDATORS, useExisting: forwardRef(() => NgxsmkTelInputComponent), multi: true}
95
- ],
96
- styles: [`
97
- /* ---------- Theme tokens ---------- */
98
- :host {
99
- --tel-bg: #fff;
100
- --tel-fg: #0f172a;
101
- --tel-border: #c0c0c0;
102
- --tel-border-hover: #9aa0a6;
103
- --tel-ring: #2563eb;
104
- --tel-placeholder: #9ca3af;
105
- --tel-error: #ef4444;
106
- --tel-radius: 12px;
107
- --tel-focus-shadow: 0 0 0 3px rgba(37, 99, 235, .25);
108
-
109
- --tel-dd-bg: var(--tel-bg);
110
- --tel-dd-border: var(--tel-border);
111
- --tel-dd-shadow: 0 24px 60px rgba(0, 0, 0, .18);
112
- --tel-dd-radius: 12px;
113
- --tel-dd-item-hover: rgba(37, 99, 235, .08);
114
- --tel-dd-z: 2000;
115
- --tel-dd-search-bg: rgba(148, 163, 184, .08);
116
-
117
- display: block;
118
- }
119
-
120
- :host-context(.dark) {
121
- --tel-bg: #0b0f17;
122
- --tel-fg: #e5e7eb;
123
- --tel-border: #334155;
124
- --tel-border-hover: #475569;
125
- --tel-ring: #60a5fa;
126
- --tel-placeholder: #94a3b8;
127
-
128
- --tel-dd-bg: #0f1521;
129
- --tel-dd-border: #324056;
130
- --tel-dd-search-bg: rgba(148, 163, 184, .12);
131
- }
132
-
133
- /* ---------- Structure ---------- */
134
- .ngxsmk-tel {
135
- width: 100%;
136
- color: var(--tel-fg);
137
- }
138
-
139
- .ngxsmk-tel.disabled {
140
- opacity: .7;
141
- cursor: not-allowed;
142
- }
143
-
144
- .ngxsmk-tel__label {
145
- display: inline-block;
146
- margin-bottom: 6px;
147
- font-size: .875rem;
148
- font-weight: 500;
149
- }
150
-
151
- .ngxsmk-tel__wrap {
152
- position: relative;
153
- }
154
-
155
- .ngxsmk-tel-input__wrapper, :host ::ng-deep .iti {
156
- width: 100%;
157
- }
158
-
159
- .ngxsmk-tel-input__control {
160
- width: 100%;
161
- height: 40px;
162
- font: inherit;
163
- color: var(--tel-fg);
164
- background: var(--tel-bg);
165
- border: 1px solid var(--tel-border);
166
- border-radius: var(--tel-radius);
167
- padding: 10px 40px 10px 12px;
168
- outline: none;
169
- transition: border-color .15s, box-shadow .15s, background .15s;
170
- }
171
-
172
- .ngxsmk-tel-input__control::placeholder {
173
- color: var(--tel-placeholder);
174
- }
175
-
176
- .ngxsmk-tel-input__control:hover {
177
- border-color: var(--tel-border-hover);
178
- }
179
-
180
- .ngxsmk-tel-input__control:focus {
181
- border-color: var(--tel-ring);
182
- box-shadow: var(--tel-focus-shadow);
183
- }
184
-
185
- [data-size="sm"] .ngxsmk-tel-input__control {
186
- height: 34px;
187
- font-size: 13px;
188
- padding: 6px 36px 6px 10px;
189
- border-radius: 10px;
190
- }
191
-
192
- [data-size="lg"] .ngxsmk-tel-input__control {
193
- height: 46px;
194
- font-size: 16px;
195
- padding: 12px 44px 12px 14px;
196
- border-radius: 14px;
197
- }
198
-
199
- [data-variant="filled"] .ngxsmk-tel-input__control {
200
- background: rgba(148, 163, 184, .08);
201
- }
202
-
203
- [data-variant="underline"] .ngxsmk-tel-input__control {
204
- border: 0;
205
- border-bottom: 2px solid var(--tel-border);
206
- border-radius: 0;
207
- padding-left: 0;
208
- padding-right: 34px;
209
- }
210
-
211
- [data-variant="underline"] .ngxsmk-tel-input__control:focus {
212
- border-bottom-color: var(--tel-ring);
213
- box-shadow: none;
214
- }
215
-
216
- /* ---------- intl-tel-input dropdown (deep selectors) ---------- */
217
- :host ::ng-deep .iti__flag-container {
218
- border-top-left-radius: var(--tel-radius);
219
- border-bottom-left-radius: var(--tel-radius);
220
- border: 1px solid var(--tel-border);
221
- border-right: none;
222
- background: var(--tel-bg);
223
- }
224
-
225
- :host ::ng-deep .iti__selected-flag {
226
- height: 100%;
227
- padding: 0 10px;
228
- display: inline-flex;
229
- align-items: center;
230
- }
231
-
232
- :host ::ng-deep .iti__country-list {
233
- background: var(--tel-dd-bg);
234
- border: 1px solid var(--tel-dd-border);
235
- border-radius: var(--tel-dd-radius);
236
- box-shadow: var(--tel-dd-shadow);
237
- max-height: min(50vh, 360px);
238
- overflow: auto;
239
- padding: 6px 0;
240
- width: max(280px, 100%);
241
- z-index: var(--tel-dd-z);
242
- }
243
-
244
- :host ::ng-deep .iti--container .iti__country-list {
245
- z-index: var(--tel-dd-z);
246
- }
247
-
248
- :host ::ng-deep .iti__search-input {
249
- position: sticky;
250
- top: 0;
251
- margin: 0;
252
- padding: 10px 12px;
253
- width: 100%;
254
- border: 0;
255
- border-bottom: 1px solid var(--tel-dd-border);
256
- outline: none;
257
- background: var(--tel-dd-search-bg);
258
- color: var(--tel-fg);
259
- }
260
-
261
- :host ::ng-deep .iti__country {
262
- display: grid;
263
- grid-template-columns: 28px 1fr auto;
264
- align-items: center;
265
- column-gap: .5rem;
266
- padding: 10px 12px;
267
- cursor: pointer;
268
- }
269
-
270
- :host ::ng-deep .iti__dial-code {
271
- color: var(--tel-placeholder);
272
- font-weight: 600;
273
- margin-left: 10px;
274
- }
275
-
276
- .ngxsmk-tel__clear {
277
- position: absolute;
278
- right: 8px;
279
- top: 50%;
280
- transform: translateY(-50%);
281
- border: 0;
282
- background: transparent;
283
- font-size: 18px;
284
- line-height: 1;
285
- width: 28px;
286
- height: 28px;
287
- border-radius: 50%;
288
- cursor: pointer;
289
- color: var(--tel-placeholder);
290
- }
291
-
292
- .ngxsmk-tel__clear:hover {
293
- background: rgba(148, 163, 184, .15);
294
- }
295
-
296
- .ngxsmk-tel__hint {
297
- margin-top: 6px;
298
- font-size: 12px;
299
- color: var(--tel-placeholder);
300
- }
301
-
302
- .ngxsmk-tel__error {
303
- margin-top: 6px;
304
- font-size: 12px;
305
- color: var(--tel-error);
306
- }
307
-
308
- .ngxsmk-tel__wrap.has-error .ngxsmk-tel-input__control {
309
- border-color: var(--tel-error);
310
- box-shadow: 0 0 0 3px rgba(239, 68, 68, .15);
311
- }
312
- `]
96
+ ]
313
97
  })
314
98
  export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDestroy, ControlValueAccessor, Validator {
99
+
315
100
  @ViewChild('telInput', {static: true}) inputRef!: ElementRef<HTMLInputElement>;
316
101
 
317
102
  /* Core config */
318
103
  @Input() initialCountry: CountryCode | 'auto' = 'US';
319
104
  @Input() preferredCountries: CountryCode[] = ['US', 'GB'];
320
105
  @Input() onlyCountries?: CountryCode[];
321
- @Input() nationalMode = false;
322
- @Input() separateDialCode = false;
323
- @Input() allowDropdown = true;
106
+ @Input() nationalMode: boolean = false;
107
+ @Input() separateDialCode: boolean = false;
108
+ @Input() allowDropdown: boolean = true;
324
109
 
325
110
  /* UX */
326
- @Input() placeholder?: string; // keep undefined to let plugin set example placeholders (requires utilsScript)
111
+ @Input() placeholder?: string;
327
112
  @Input() autocomplete = 'tel';
328
113
  @Input() name?: string;
329
114
  @Input() inputId?: string;
330
- @Input() disabled = false;
115
+ @Input() disabled: boolean = false;
331
116
 
332
117
  @Input() label?: string;
333
118
  @Input() hint?: string;
334
119
  @Input() errorText?: string;
335
120
  @Input() size: 'sm' | 'md' | 'lg' = 'md';
336
121
  @Input() variant: 'outline' | 'filled' | 'underline' = 'outline';
337
- @Input() showClear = true;
338
- @Input() autoFocus = false;
339
- @Input() selectOnFocus = false;
340
- @Input() formatOnBlur = true;
341
- @Input() showErrorWhenTouched = true;
122
+ @Input() showClear: boolean = true;
123
+ @Input() autoFocus: boolean = false;
124
+ @Input() selectOnFocus: boolean = false;
125
+ @Input() formatOnBlur: boolean = true;
126
+ @Input() showErrorWhenTouched: boolean = true;
342
127
 
343
128
  /* Dropdown plumbing */
344
- @Input() dropdownAttachToBody = true;
345
- @Input() dropdownZIndex = 2000;
129
+ @Input() dropdownAttachToBody: boolean = true;
130
+ @Input() dropdownZIndex: number = 2000;
346
131
 
347
132
  /* Localization + RTL */
348
133
  @Input('i18n') i18n?: IntlTelI18n;
@@ -357,7 +142,7 @@ export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDest
357
142
  this.localizedCountries = v;
358
143
  }
359
144
 
360
- @Input() clearAriaLabel = 'Clear phone number';
145
+ @Input() clearAriaLabel: string = 'Clear phone number';
361
146
  @Input() dir: 'ltr' | 'rtl' = 'ltr';
362
147
 
363
148
  /* Placeholders (intl-tel-input) */
@@ -365,9 +150,11 @@ export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDest
365
150
  @Input() utilsScript?: string;
366
151
  @Input() customPlaceholder?: (example: string, country: any) => string;
367
152
 
153
+ @Input() formatWhenValid: 'off' | 'blur' | 'typing' = 'blur';
154
+
368
155
  /* Digits-only controls */
369
- @Input() digitsOnly = true;
370
- @Input() allowLeadingPlus = true;
156
+ @Input() digitsOnly: boolean = true;
157
+ @Input() allowLeadingPlus: boolean = true;
371
158
 
372
159
  /* Outputs */
373
160
  @Output() countryChange = new EventEmitter<{ iso2: CountryCode }>();
@@ -383,9 +170,9 @@ export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDest
383
170
  private validatorChange?: () => void;
384
171
  private lastEmittedValid = false;
385
172
  private pendingWrite: string | null = null;
386
- private touched = false;
173
+ private touched: boolean = false;
387
174
 
388
- readonly resolvedId = this.inputId || ('tel-' + Math.random().toString(36).slice(2));
175
+ readonly resolvedId: string = this.inputId || ('tel-' + Math.random().toString(36).slice(2));
389
176
 
390
177
  constructor(
391
178
  private readonly zone: NgZone,
@@ -394,8 +181,12 @@ export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDest
394
181
  ) {
395
182
  }
396
183
 
397
- async ngAfterViewInit() {
184
+ ngAfterViewInit(): void {
398
185
  if (!isPlatformBrowser(this.platformId)) return;
186
+ void this.initAndWire();
187
+ }
188
+
189
+ private async initAndWire(): Promise<void> {
399
190
  await this.initIntlTelInput();
400
191
  this.bindDomListeners();
401
192
 
@@ -491,8 +282,17 @@ export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDest
491
282
  private async initIntlTelInput() {
492
283
  const [{default: intlTelInput}] = await Promise.all([import('intl-tel-input')]);
493
284
 
494
- const toLowerKeys = (m?: CountryMap) =>
495
- m ? Object.fromEntries(Object.entries(m).map(([k, v]) => [k.toLowerCase(), v])) : undefined;
285
+ const toLowerKeys = (m?: CountryMap) => {
286
+ if (!m) return undefined;
287
+ const out: Record<string, string> = {};
288
+ for (const k in m) {
289
+ if (Object.prototype.hasOwnProperty.call(m, k)) {
290
+ const v = (m as Record<string, string | undefined>)[k];
291
+ if (v != null) out[k.toLowerCase()] = v;
292
+ }
293
+ }
294
+ return out;
295
+ };
496
296
 
497
297
  const config: any = {
498
298
  initialCountry: this.initialCountry === 'auto' ? 'auto' : (this.initialCountry?.toLowerCase() || 'us'),
@@ -503,8 +303,8 @@ export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDest
503
303
  separateDialCode: this.separateDialCode,
504
304
  geoIpLookup: (cb: (iso2: string) => void) => cb('us'),
505
305
 
506
- // placeholders — NOTE: no CDN fallback anymore
507
- autoPlaceholder: this.autoPlaceholder, // 'off' | 'polite' | 'aggressive'
306
+ // placeholders
307
+ autoPlaceholder: this.autoPlaceholder,
508
308
  utilsScript: this.utilsScript,
509
309
  customPlaceholder: this.customPlaceholder,
510
310
 
@@ -520,7 +320,6 @@ export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDest
520
320
  this.iti = intlTelInput(this.inputRef.nativeElement, config);
521
321
  });
522
322
 
523
- // z-index for dropdown
524
323
  (this.inputRef.nativeElement as HTMLElement).style.setProperty('--tel-dd-z', String(this.dropdownZIndex));
525
324
  }
526
325
 
@@ -551,8 +350,7 @@ export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDest
551
350
  // ----- Input filtering (digits-only) -----
552
351
  private sanitizeDigits(value: string): string {
553
352
  if (!this.digitsOnly) return value;
554
- let v = value.replace(/[^\d+]/g, ''); // keep digits and pluses
555
- // allow only ONE leading + (if enabled)
353
+ let v = value.replace(/[^\d+]/g, '');
556
354
  if (this.allowLeadingPlus) {
557
355
  const hasLeadingPlus = v.startsWith('+');
558
356
  v = (hasLeadingPlus ? '+' : '') + v.replace(/\+/g, '');
@@ -566,12 +364,9 @@ export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDest
566
364
  const el = this.inputRef.nativeElement;
567
365
 
568
366
  this.zone.runOutsideAngular(() => {
569
- // prevent invalid chars while typing
570
367
  el.addEventListener('beforeinput', (ev: InputEvent) => {
571
368
  if (!this.digitsOnly) return;
572
369
  const data = (ev as any).data as string | null;
573
-
574
- // allow deletions, cuts, etc.
575
370
  if (!data || ev.inputType !== 'insertText') return;
576
371
 
577
372
  const pos = el.selectionStart ?? 0;
@@ -581,7 +376,6 @@ export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDest
581
376
  if (!isDigit && !isPlusAtStart) ev.preventDefault();
582
377
  });
583
378
 
584
- // sanitize pastes
585
379
  el.addEventListener('paste', (e: ClipboardEvent) => {
586
380
  if (!this.digitsOnly) return;
587
381
  e.preventDefault();
@@ -593,7 +387,6 @@ export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDest
593
387
  queueMicrotask(() => this.handleInput());
594
388
  });
595
389
 
596
- // catch any remaining non-digit changes (e.g., programmatic)
597
390
  el.addEventListener('input', () => {
598
391
  if (this.digitsOnly) {
599
392
  const val = el.value;