ngxsmk-tel-input 1.0.9 → 1.1.1
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/README.md +3 -3
- package/package.json +28 -5
- package/src/lib/ngxsmk-tel-input.component.ts +181 -56
package/README.md
CHANGED
|
@@ -10,9 +10,9 @@ Wraps [`intl-tel-input`](https://github.com/jackocnr/intl-tel-input) for the UI
|
|
|
10
10
|
## Screenshots
|
|
11
11
|
|
|
12
12
|
<p align="left">
|
|
13
|
-
<img src="https://unpkg.com/ngxsmk-tel-input@
|
|
13
|
+
<img src="https://unpkg.com/ngxsmk-tel-input@latest/docs/valid.png" alt="Angular international phone input - valid" width="420" />
|
|
14
14
|
|
|
15
|
-
<img src="https://unpkg.com/ngxsmk-tel-input@
|
|
15
|
+
<img src="https://unpkg.com/ngxsmk-tel-input@latest/docs/invalid.png" alt="Angular international phone input - Invalid" width="420" />
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
18
|
---
|
|
@@ -157,7 +157,7 @@ export class AppComponent {
|
|
|
157
157
|
|
|
158
158
|
You can localize the dropdown/search labels and override country names.
|
|
159
159
|
|
|
160
|
-
<img src="https://unpkg.com/ngxsmk-tel-input@
|
|
160
|
+
<img src="https://unpkg.com/ngxsmk-tel-input@latest/docs/kr.png" alt="Angular international phone input - Korean Localization & RTL" width="420" />
|
|
161
161
|
|
|
162
162
|
Korean example
|
|
163
163
|
|
package/package.json
CHANGED
|
@@ -1,20 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ngxsmk-tel-input",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
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
|
+
"ngxsmk-tel-input",
|
|
7
|
+
"ngx",
|
|
6
8
|
"angular",
|
|
9
|
+
"angular17",
|
|
10
|
+
"angular18",
|
|
11
|
+
"angular19",
|
|
7
12
|
"angular-forms",
|
|
13
|
+
"reactive-forms",
|
|
14
|
+
"template-driven-forms",
|
|
8
15
|
"controlvalueaccessor",
|
|
16
|
+
"cva",
|
|
9
17
|
"phone-input",
|
|
10
|
-
"telephone",
|
|
11
|
-
"
|
|
12
|
-
"international",
|
|
18
|
+
"telephone-input",
|
|
19
|
+
"phone-number",
|
|
20
|
+
"international-phone",
|
|
13
21
|
"intl-tel-input",
|
|
14
22
|
"libphonenumber",
|
|
23
|
+
"libphonenumber-js",
|
|
15
24
|
"e164",
|
|
25
|
+
"phone-validation",
|
|
16
26
|
"phone-number-validation",
|
|
17
|
-
"country-
|
|
27
|
+
"country-code",
|
|
28
|
+
"dial-code",
|
|
29
|
+
"separate-dial-code",
|
|
30
|
+
"national-mode",
|
|
31
|
+
"country-flags",
|
|
32
|
+
"dropdown",
|
|
33
|
+
"i18n",
|
|
34
|
+
"localization",
|
|
35
|
+
"rtl",
|
|
36
|
+
"a11y",
|
|
37
|
+
"accessibility",
|
|
38
|
+
"ssr",
|
|
39
|
+
"angular-universal",
|
|
40
|
+
"typescript"
|
|
18
41
|
],
|
|
19
42
|
"homepage": "https://github.com/toozuuu/ngxsmk-tel-input#readme",
|
|
20
43
|
"repository": {
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
SimpleChanges,
|
|
15
15
|
ViewChild
|
|
16
16
|
} from '@angular/core';
|
|
17
|
-
import {
|
|
17
|
+
import {isPlatformBrowser} from '@angular/common';
|
|
18
18
|
import {
|
|
19
19
|
AbstractControl,
|
|
20
20
|
ControlValueAccessor,
|
|
@@ -23,8 +23,8 @@ import {
|
|
|
23
23
|
ValidationErrors,
|
|
24
24
|
Validator
|
|
25
25
|
} from '@angular/forms';
|
|
26
|
-
import type {
|
|
27
|
-
import {
|
|
26
|
+
import type {CountryCode} from 'libphonenumber-js';
|
|
27
|
+
import {NgxsmkTelInputService} from './ngxsmk-tel-input.service';
|
|
28
28
|
|
|
29
29
|
type IntlTelInstance = any;
|
|
30
30
|
export type CountryMap = Partial<Record<CountryCode, string>>;
|
|
@@ -90,8 +90,8 @@ export interface IntlTelI18n {
|
|
|
90
90
|
</div>
|
|
91
91
|
`,
|
|
92
92
|
providers: [
|
|
93
|
-
{
|
|
94
|
-
{
|
|
93
|
+
{provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NgxsmkTelInputComponent), multi: true},
|
|
94
|
+
{provide: NG_VALIDATORS, useExisting: forwardRef(() => NgxsmkTelInputComponent), multi: true}
|
|
95
95
|
],
|
|
96
96
|
styles: [`
|
|
97
97
|
/* ---------- Theme tokens ---------- */
|
|
@@ -131,37 +131,87 @@ export interface IntlTelI18n {
|
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
/* ---------- Structure ---------- */
|
|
134
|
-
.ngxsmk-tel {
|
|
135
|
-
|
|
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
|
+
}
|
|
136
143
|
|
|
137
|
-
.ngxsmk-tel__label {
|
|
138
|
-
|
|
139
|
-
|
|
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
|
+
}
|
|
140
158
|
|
|
141
159
|
.ngxsmk-tel-input__control {
|
|
142
|
-
width: 100%;
|
|
143
|
-
|
|
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);
|
|
144
166
|
border-radius: var(--tel-radius);
|
|
145
167
|
padding: 10px 40px 10px 12px;
|
|
146
168
|
outline: none;
|
|
147
169
|
transition: border-color .15s, box-shadow .15s, background .15s;
|
|
148
170
|
}
|
|
149
|
-
|
|
150
|
-
.ngxsmk-tel-input__control
|
|
151
|
-
|
|
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
|
+
}
|
|
152
184
|
|
|
153
185
|
[data-size="sm"] .ngxsmk-tel-input__control {
|
|
154
|
-
height: 34px;
|
|
186
|
+
height: 34px;
|
|
187
|
+
font-size: 13px;
|
|
188
|
+
padding: 6px 36px 6px 10px;
|
|
189
|
+
border-radius: 10px;
|
|
155
190
|
}
|
|
191
|
+
|
|
156
192
|
[data-size="lg"] .ngxsmk-tel-input__control {
|
|
157
|
-
height: 46px;
|
|
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);
|
|
158
201
|
}
|
|
159
202
|
|
|
160
|
-
[data-variant="filled"] .ngxsmk-tel-input__control { background: rgba(148, 163, 184, .08); }
|
|
161
203
|
[data-variant="underline"] .ngxsmk-tel-input__control {
|
|
162
|
-
border: 0;
|
|
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;
|
|
163
214
|
}
|
|
164
|
-
[data-variant="underline"] .ngxsmk-tel-input__control:focus { border-bottom-color: var(--tel-ring); box-shadow: none; }
|
|
165
215
|
|
|
166
216
|
/* ---------- intl-tel-input dropdown (deep selectors) ---------- */
|
|
167
217
|
:host ::ng-deep .iti__flag-container {
|
|
@@ -171,37 +221,89 @@ export interface IntlTelI18n {
|
|
|
171
221
|
border-right: none;
|
|
172
222
|
background: var(--tel-bg);
|
|
173
223
|
}
|
|
174
|
-
|
|
224
|
+
|
|
225
|
+
:host ::ng-deep .iti__selected-flag {
|
|
226
|
+
height: 100%;
|
|
227
|
+
padding: 0 10px;
|
|
228
|
+
display: inline-flex;
|
|
229
|
+
align-items: center;
|
|
230
|
+
}
|
|
175
231
|
|
|
176
232
|
:host ::ng-deep .iti__country-list {
|
|
177
|
-
background: var(--tel-dd-bg);
|
|
178
|
-
border
|
|
179
|
-
|
|
180
|
-
|
|
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);
|
|
181
246
|
}
|
|
182
|
-
:host ::ng-deep .iti--container .iti__country-list { z-index: var(--tel-dd-z); }
|
|
183
247
|
|
|
184
248
|
:host ::ng-deep .iti__search-input {
|
|
185
|
-
position: sticky;
|
|
186
|
-
|
|
187
|
-
|
|
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);
|
|
188
259
|
}
|
|
189
260
|
|
|
190
261
|
:host ::ng-deep .iti__country {
|
|
191
|
-
display: grid;
|
|
192
|
-
|
|
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;
|
|
193
274
|
}
|
|
194
|
-
:host ::ng-deep .iti__dial-code { color: var(--tel-placeholder); font-weight: 600; margin-left: 10px; }
|
|
195
275
|
|
|
196
276
|
.ngxsmk-tel__clear {
|
|
197
|
-
position: absolute;
|
|
198
|
-
|
|
199
|
-
|
|
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);
|
|
200
300
|
}
|
|
201
|
-
.ngxsmk-tel__clear:hover { background: rgba(148, 163, 184, .15); }
|
|
202
301
|
|
|
203
|
-
.ngxsmk-
|
|
204
|
-
|
|
302
|
+
.ngxsmk-tel__error {
|
|
303
|
+
margin-top: 6px;
|
|
304
|
+
font-size: 12px;
|
|
305
|
+
color: var(--tel-error);
|
|
306
|
+
}
|
|
205
307
|
|
|
206
308
|
.ngxsmk-tel__wrap.has-error .ngxsmk-tel-input__control {
|
|
207
309
|
border-color: var(--tel-error);
|
|
@@ -210,7 +312,7 @@ export interface IntlTelI18n {
|
|
|
210
312
|
`]
|
|
211
313
|
})
|
|
212
314
|
export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDestroy, ControlValueAccessor, Validator {
|
|
213
|
-
@ViewChild('telInput', {
|
|
315
|
+
@ViewChild('telInput', {static: true}) inputRef!: ElementRef<HTMLInputElement>;
|
|
214
316
|
|
|
215
317
|
/* Core config */
|
|
216
318
|
@Input() initialCountry: CountryCode | 'auto' = 'US';
|
|
@@ -244,9 +346,17 @@ export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDest
|
|
|
244
346
|
|
|
245
347
|
/* Localization + RTL */
|
|
246
348
|
@Input('i18n') i18n?: IntlTelI18n;
|
|
247
|
-
|
|
349
|
+
|
|
350
|
+
@Input('telI18n') set telI18n(v: IntlTelI18n | undefined) {
|
|
351
|
+
this.i18n = v;
|
|
352
|
+
}
|
|
353
|
+
|
|
248
354
|
@Input('localizedCountries') localizedCountries?: CountryMap;
|
|
249
|
-
|
|
355
|
+
|
|
356
|
+
@Input('telLocalizedCountries') set telLocalizedCountries(v: CountryMap | undefined) {
|
|
357
|
+
this.localizedCountries = v;
|
|
358
|
+
}
|
|
359
|
+
|
|
250
360
|
@Input() clearAriaLabel = 'Clear phone number';
|
|
251
361
|
@Input() dir: 'ltr' | 'rtl' = 'ltr';
|
|
252
362
|
|
|
@@ -266,8 +376,10 @@ export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDest
|
|
|
266
376
|
|
|
267
377
|
/* Internal */
|
|
268
378
|
private iti: IntlTelInstance | null = null;
|
|
269
|
-
private onChange: (val: string | null) => void = () => {
|
|
270
|
-
|
|
379
|
+
private onChange: (val: string | null) => void = () => {
|
|
380
|
+
};
|
|
381
|
+
private onTouchedCb: () => void = () => {
|
|
382
|
+
};
|
|
271
383
|
private validatorChange?: () => void;
|
|
272
384
|
private lastEmittedValid = false;
|
|
273
385
|
private pendingWrite: string | null = null;
|
|
@@ -279,7 +391,8 @@ export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDest
|
|
|
279
391
|
private readonly zone: NgZone,
|
|
280
392
|
private readonly tel: NgxsmkTelInputService,
|
|
281
393
|
@Inject(PLATFORM_ID) private readonly platformId: Object
|
|
282
|
-
) {
|
|
394
|
+
) {
|
|
395
|
+
}
|
|
283
396
|
|
|
284
397
|
async ngAfterViewInit() {
|
|
285
398
|
if (!isPlatformBrowser(this.platformId)) return;
|
|
@@ -297,11 +410,11 @@ export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDest
|
|
|
297
410
|
ngOnChanges(changes: SimpleChanges): void {
|
|
298
411
|
if (!isPlatformBrowser(this.platformId)) return;
|
|
299
412
|
const configChanged = [
|
|
300
|
-
'initialCountry','preferredCountries','onlyCountries',
|
|
301
|
-
'separateDialCode','allowDropdown','nationalMode',
|
|
302
|
-
'i18n','localizedCountries','dir',
|
|
303
|
-
'autoPlaceholder','utilsScript','customPlaceholder',
|
|
304
|
-
'digitsOnly','allowLeadingPlus'
|
|
413
|
+
'initialCountry', 'preferredCountries', 'onlyCountries',
|
|
414
|
+
'separateDialCode', 'allowDropdown', 'nationalMode',
|
|
415
|
+
'i18n', 'localizedCountries', 'dir',
|
|
416
|
+
'autoPlaceholder', 'utilsScript', 'customPlaceholder',
|
|
417
|
+
'digitsOnly', 'allowLeadingPlus'
|
|
305
418
|
].some(k => k in changes && !changes[k]?.firstChange);
|
|
306
419
|
if (configChanged && this.iti) {
|
|
307
420
|
this.reinitPlugin();
|
|
@@ -322,8 +435,15 @@ export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDest
|
|
|
322
435
|
}
|
|
323
436
|
this.setInputValue(val ?? '');
|
|
324
437
|
}
|
|
325
|
-
|
|
326
|
-
|
|
438
|
+
|
|
439
|
+
registerOnChange(fn: any): void {
|
|
440
|
+
this.onChange = fn;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
registerOnTouched(fn: any): void {
|
|
444
|
+
this.onTouchedCb = fn;
|
|
445
|
+
}
|
|
446
|
+
|
|
327
447
|
setDisabledState(isDisabled: boolean): void {
|
|
328
448
|
this.disabled = isDisabled;
|
|
329
449
|
if (this.inputRef) this.inputRef.nativeElement.disabled = isDisabled;
|
|
@@ -338,9 +458,12 @@ export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDest
|
|
|
338
458
|
this.lastEmittedValid = valid;
|
|
339
459
|
this.validityChange.emit(valid);
|
|
340
460
|
}
|
|
341
|
-
return valid ? null : {
|
|
461
|
+
return valid ? null : {phoneInvalid: true};
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
registerOnValidatorChange(fn: () => void): void {
|
|
465
|
+
this.validatorChange = fn;
|
|
342
466
|
}
|
|
343
|
-
registerOnValidatorChange(fn: () => void): void { this.validatorChange = fn; }
|
|
344
467
|
|
|
345
468
|
// ----- Public helpers -----
|
|
346
469
|
focus(): void {
|
|
@@ -350,12 +473,14 @@ export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDest
|
|
|
350
473
|
queueMicrotask(() => el.setSelectionRange(0, el.value.length));
|
|
351
474
|
}
|
|
352
475
|
}
|
|
476
|
+
|
|
353
477
|
selectCountry(iso2: CountryCode): void {
|
|
354
478
|
if (this.iti) {
|
|
355
479
|
this.iti.setCountry(iso2.toLowerCase());
|
|
356
480
|
this.handleInput();
|
|
357
481
|
}
|
|
358
482
|
}
|
|
483
|
+
|
|
359
484
|
clearInput() {
|
|
360
485
|
this.setInputValue('');
|
|
361
486
|
this.handleInput();
|
|
@@ -364,7 +489,7 @@ export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDest
|
|
|
364
489
|
|
|
365
490
|
// ----- Plugin wiring -----
|
|
366
491
|
private async initIntlTelInput() {
|
|
367
|
-
const [{
|
|
492
|
+
const [{default: intlTelInput}] = await Promise.all([import('intl-tel-input')]);
|
|
368
493
|
|
|
369
494
|
const toLowerKeys = (m?: CountryMap) =>
|
|
370
495
|
m ? Object.fromEntries(Object.entries(m).map(([k, v]) => [k.toLowerCase(), v])) : undefined;
|
|
@@ -485,7 +610,7 @@ export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDest
|
|
|
485
610
|
el.addEventListener('countrychange', () => {
|
|
486
611
|
const iso2 = this.currentIso2();
|
|
487
612
|
this.zone.run(() => {
|
|
488
|
-
this.countryChange.emit({
|
|
613
|
+
this.countryChange.emit({iso2});
|
|
489
614
|
this.validatorChange?.();
|
|
490
615
|
});
|
|
491
616
|
this.handleInput();
|
|
@@ -519,7 +644,7 @@ export class NgxsmkTelInputComponent implements AfterViewInit, OnChanges, OnDest
|
|
|
519
644
|
const iso2 = this.currentIso2();
|
|
520
645
|
const parsed = this.tel.parse(raw, iso2);
|
|
521
646
|
this.zone.run(() => this.onChange(parsed.e164)); // E.164 or null
|
|
522
|
-
this.zone.run(() => this.inputChange.emit({
|
|
647
|
+
this.zone.run(() => this.inputChange.emit({raw, e164: parsed.e164, iso2}));
|
|
523
648
|
if (raw && this.nationalMode && parsed.national) {
|
|
524
649
|
const normalized = parsed.national.replace(/\s{2,}/g, ' ');
|
|
525
650
|
if (normalized !== raw) this.setInputValue(normalized);
|