svelte-tel-input 3.5.1 → 3.6.0

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 CHANGED
@@ -63,12 +63,12 @@ _Snippet would be too long_ - [Example](https://github.com/gyurielf/svelte-tel-i
63
63
  name="Country"
64
64
  bind:value={selectedCountry}
65
65
  >
66
- <option value={null} hidden={country !== null}>Please select</option>
66
+ <option value={null} hidden={selectedCountry !== null}>Please select</option>
67
67
  {#each normalizedCountries as currentCountry (currentCountry.id)}
68
68
  <option
69
69
  value={currentCountry.iso2}
70
- selected={currentCountry.iso2 === country}
71
- aria-selected={currentCountry.iso2 === country}
70
+ selected={currentCountry.iso2 === selectedCountry}
71
+ aria-selected={currentCountry.iso2 === selectedCountry}
72
72
  >
73
73
  {currentCountry.iso2} (+{currentCountry.dialCode})
74
74
  </option>
@@ -79,7 +79,7 @@ _Snippet would be too long_ - [Example](https://github.com/gyurielf/svelte-tel-i
79
79
  bind:value
80
80
  bind:valid
81
81
  bind:detailedValue
82
- class="basic-tel-input {!isValid ? 'invalid' : ''}"
82
+ class="basic-tel-input {!valid ? 'invalid' : ''}"
83
83
  />
84
84
  </div>
85
85
 
@@ -1,17 +1,19 @@
1
- <script>import { createEventDispatcher, onMount } from "svelte";
1
+ <script>import { createEventDispatcher, onMount, tick } from "svelte";
2
2
  import { parsePhoneNumberWithError, ParseError } from "libphonenumber-js/max";
3
3
  import {
4
4
  normalizeTelInput,
5
5
  getCountryForPartialE164Number,
6
6
  generatePlaceholder,
7
- telInputAction
7
+ telInputAction,
8
+ allowedCharacters
8
9
  } from "../../utils/index.js";
9
10
  const dispatch = createEventDispatcher();
10
11
  const defaultOptions = {
11
12
  autoPlaceholder: true,
12
13
  spaces: true,
13
14
  invalidateOnCountryChange: false,
14
- format: "national"
15
+ format: "national",
16
+ strictCountry: false
15
17
  };
16
18
  export let autocomplete = null;
17
19
  let classes = "";
@@ -44,19 +46,34 @@ const updateCountry = (countryCode) => {
44
46
  country = countryCode;
45
47
  prevCountry = country;
46
48
  dispatch("updateCountry", country);
49
+ dispatch("updateDetailedValue", detailedValue);
47
50
  }
48
51
  return country;
49
52
  };
50
- const handleParsePhoneNumber = (rawInput, currCountry = null) => {
53
+ const findNewCursorPosition = (newValue, formattedValue, initialCursorPosition) => {
54
+ let fvIndex = 0;
55
+ for (let nvIndex = 0; nvIndex < initialCursorPosition; nvIndex++) {
56
+ const nvChar = allowedCharacters(newValue[nvIndex], { spaces: false });
57
+ if (nvChar >= "0" && nvChar <= "9") {
58
+ while (!(formattedValue[fvIndex] >= "0" && formattedValue[fvIndex] <= "9") && fvIndex < formattedValue.length) {
59
+ fvIndex++;
60
+ }
61
+ fvIndex++;
62
+ }
63
+ }
64
+ return fvIndex;
65
+ };
66
+ const handleParsePhoneNumber = async (rawInput, currCountry = null) => {
51
67
  const input = rawInput;
52
68
  if (input !== null) {
53
- const numberHasCountry = getCountryForPartialE164Number(input);
54
- if (numberHasCountry && numberHasCountry !== prevCountry) {
55
- updateCountry(numberHasCountry);
69
+ const detectedCountry = getCountryForPartialE164Number(input);
70
+ const useCountry = options?.strictCountry ? currCountry : detectedCountry ?? currCountry;
71
+ if (!options?.strictCountry && detectedCountry && detectedCountry !== prevCountry) {
72
+ updateCountry(detectedCountry);
56
73
  }
57
74
  try {
58
75
  detailedValue = normalizeTelInput(
59
- parsePhoneNumberWithError(input, numberHasCountry ?? currCountry ?? void 0)
76
+ parsePhoneNumberWithError(input, useCountry ?? void 0)
60
77
  );
61
78
  } catch (err) {
62
79
  if (err instanceof ParseError) {
@@ -71,10 +88,31 @@ const handleParsePhoneNumber = (rawInput, currCountry = null) => {
71
88
  }
72
89
  const formatOption = combinedOptions.format === "national" ? "nationalNumber" : "e164";
73
90
  const formattedValue = combinedOptions.format === "national" ? "formatOriginal" : "formatInternational";
91
+ const initialCursorPosition = el?.selectionStart || 0;
74
92
  if (combinedOptions.spaces && detailedValue?.[formattedValue]) {
75
93
  inputValue = detailedValue[formattedValue] ?? null;
94
+ await tick();
95
+ if (el) {
96
+ const newCursorPosition = findNewCursorPosition(
97
+ input,
98
+ inputValue,
99
+ initialCursorPosition
100
+ );
101
+ el.selectionStart = newCursorPosition;
102
+ el.selectionEnd = newCursorPosition;
103
+ }
76
104
  } else if (detailedValue?.[formatOption]) {
77
105
  inputValue = detailedValue[formatOption] ?? null;
106
+ await tick();
107
+ if (el) {
108
+ const newCursorPosition = findNewCursorPosition(
109
+ input,
110
+ inputValue,
111
+ initialCursorPosition
112
+ );
113
+ el.selectionStart = newCursorPosition;
114
+ el.selectionEnd = newCursorPosition;
115
+ }
78
116
  }
79
117
  value = detailedValue?.e164 ?? input ?? null;
80
118
  valid = detailedValue?.isValid ?? false;
@@ -124,13 +162,16 @@ export const updateValue = (newValue, newCountry) => {
124
162
  if (castedValue) {
125
163
  handleParsePhoneNumber(
126
164
  castedValue,
127
- getCountryForPartialE164Number(castedValue) || newCountry
165
+ options?.strictCountry ? country : getCountryForPartialE164Number(castedValue) || newCountry
128
166
  );
129
167
  }
130
168
  };
131
169
  onMount(() => {
132
170
  if (value) {
133
- handleParsePhoneNumber(value, getCountryForPartialE164Number(value) || country);
171
+ handleParsePhoneNumber(
172
+ value,
173
+ options?.strictCountry ? country : getCountryForPartialE164Number(value) || country
174
+ );
134
175
  }
135
176
  });
136
177
  </script>
@@ -162,6 +203,7 @@ onMount(() => {
162
203
  use:telInputAction={{
163
204
  handler: handleInputAction,
164
205
  spaces: combinedOptions.spaces,
165
- value
206
+ value,
207
+ strictCountryCode: combinedOptions.strictCountry
166
208
  }}
167
209
  />
@@ -75,6 +75,11 @@ export interface TelInputOptions {
75
75
  * @default false
76
76
  */
77
77
  invalidateOnCountryChange?: boolean;
78
+ /**
79
+ * Prevent automatic country parsing from the input value. It validates via the passed `country` property value.
80
+ * @default false
81
+ */
82
+ strictCountry?: boolean;
78
83
  /**
79
84
  * "international": `+36 20 123 4567`,
80
85
  * "default": `20 123 4567`
@@ -1,8 +1,9 @@
1
1
  import type { E164Number } from 'libphonenumber-js';
2
- export declare const telInputAction: (node: HTMLInputElement, { handler, spaces }: {
2
+ export declare const telInputAction: (node: HTMLInputElement, { handler, spaces, strictCountryCode }: {
3
3
  handler: (val: string) => void;
4
4
  spaces: boolean;
5
5
  value: E164Number | null;
6
+ strictCountryCode: boolean;
6
7
  }) => {
7
8
  update(params: {
8
9
  handler: (val: string) => void;
@@ -1,11 +1,12 @@
1
1
  import { inspectAllowedChars, inputParser } from '../../index.js';
2
- export const telInputAction = (node, { handler, spaces }) => {
2
+ export const telInputAction = (node, { handler, spaces, strictCountryCode }) => {
3
3
  const onInput = (event) => {
4
4
  if (node && node.contains(event.target)) {
5
5
  const currentValue = event.target.value;
6
6
  const formattedInput = inputParser(currentValue, {
7
7
  parseCharacter: inspectAllowedChars,
8
- allowSpaces: spaces
8
+ allowSpaces: spaces,
9
+ disallowPlusSign: strictCountryCode
9
10
  });
10
11
  node.value = formattedInput;
11
12
  handler(formattedInput);
@@ -69,8 +69,9 @@ export declare const isSupportedCountry: (country: CountryCode, metadata: Metada
69
69
  export declare const allowedCharacters: (character: string, { spaces }?: {
70
70
  spaces?: boolean;
71
71
  }) => string;
72
- export declare const inputParser: (text: string, { allowSpaces, parseCharacter }: {
72
+ export declare const inputParser: (text: string, { allowSpaces, parseCharacter, disallowPlusSign }: {
73
73
  allowSpaces: boolean;
74
- parseCharacter: (char: string, val: string, allowSpaces?: boolean) => string | undefined;
74
+ disallowPlusSign: boolean;
75
+ parseCharacter: (char: string, val: string, allowSpaces: boolean, disallowPlusSign: boolean) => string | undefined;
75
76
  }) => string;
76
- export declare const inspectAllowedChars: (character: string, value: string, allowSpaces?: boolean) => string;
77
+ export declare const inspectAllowedChars: (character: string, value: string, allowSpaces: boolean, disallowPlusSign: boolean) => string;
@@ -31,16 +31,16 @@ export const normalizeTelInput = (input) => {
31
31
  isPossible: input ? input.isPossible() : false,
32
32
  phoneNumber: input ? input.number : null,
33
33
  countryCallingCode: input ? input.countryCallingCode : null,
34
- formattedNumber: input ? input.formatInternational() : null,
34
+ formattedNumber: input ? new AsYouType().input(input.number) : null,
35
35
  nationalNumber: input ? input.nationalNumber : null,
36
- formatInternational: input ? input.formatInternational() : null,
36
+ formatInternational: input ? new AsYouType().input(input.number) : null,
37
37
  formatOriginal: input
38
- ? input
39
- .formatInternational()
38
+ ? new AsYouType()
39
+ .input(input.number)
40
40
  .slice(input.countryCallingCode.length + 1)
41
41
  .trim()
42
42
  : null,
43
- formatNational: input ? input.formatNational() : null,
43
+ formatNational: input ? new AsYouType(input.country).input(input.number) : null,
44
44
  uri: input ? input.getURI() : null,
45
45
  e164: input ? input.number : null
46
46
  }).filter(([, value]) => value !== null));
@@ -265,19 +265,19 @@ export const allowedCharacters = (character, { spaces } = {
265
265
  // Allow digits
266
266
  return DIGITS[character];
267
267
  };
268
- export const inputParser = (text, { allowSpaces, parseCharacter }) => {
268
+ export const inputParser = (text, { allowSpaces, parseCharacter, disallowPlusSign }) => {
269
269
  let value = '';
270
270
  for (let index = 0; index < text.length; index++) {
271
- const character = parseCharacter(text[index], value, allowSpaces);
271
+ const character = parseCharacter(text[index], value, allowSpaces, disallowPlusSign);
272
272
  if (character !== undefined) {
273
273
  value += character;
274
274
  }
275
275
  }
276
276
  return value;
277
277
  };
278
- export const inspectAllowedChars = (character, value, allowSpaces) => {
278
+ export const inspectAllowedChars = (character, value, allowSpaces, disallowPlusSign) => {
279
279
  // Leading plus is allowed
280
- if (character === '+') {
280
+ if (!disallowPlusSign && character === '+') {
281
281
  if (!value) {
282
282
  return character;
283
283
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "svelte-tel-input",
3
3
  "description": "svelte-tel-input",
4
- "version": "3.5.1",
4
+ "version": "3.6.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/gyurielf/svelte-tel-input.git"
@@ -27,7 +27,7 @@
27
27
  "pnpm": ">= 8"
28
28
  },
29
29
  "peerDependencies": {
30
- "svelte": "^3.58.0 || ^4.0.0"
30
+ "svelte": "^3.58.0 || ^4.0.0 || ^5.0.0"
31
31
  },
32
32
  "dependencies": {
33
33
  "libphonenumber-js": "1.10.43"