svelte-tel-input 3.5.2 → 3.6.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.
@@ -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,37 @@ 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
+ if (initialCursorPosition >= newValue.length) {
55
+ return formattedValue.length;
56
+ }
57
+ let fvIndex = 0;
58
+ for (let nvIndex = 0; nvIndex < initialCursorPosition; nvIndex++) {
59
+ const nvChar = allowedCharacters(newValue[nvIndex], { spaces: false });
60
+ if (nvChar >= "0" && nvChar <= "9") {
61
+ while (!(formattedValue[fvIndex] >= "0" && formattedValue[fvIndex] <= "9") && fvIndex < formattedValue.length) {
62
+ fvIndex++;
63
+ }
64
+ fvIndex++;
65
+ }
66
+ }
67
+ return fvIndex;
68
+ };
69
+ const handleParsePhoneNumber = async (rawInput, currCountry = null) => {
51
70
  const input = rawInput;
52
71
  if (input !== null) {
53
- const numberHasCountry = getCountryForPartialE164Number(input);
54
- if (numberHasCountry && numberHasCountry !== prevCountry) {
55
- updateCountry(numberHasCountry);
72
+ const detectedCountry = getCountryForPartialE164Number(input);
73
+ const useCountry = options?.strictCountry ? currCountry : detectedCountry ?? currCountry;
74
+ if (!options?.strictCountry && detectedCountry && detectedCountry !== prevCountry) {
75
+ updateCountry(detectedCountry);
56
76
  }
57
77
  try {
58
78
  detailedValue = normalizeTelInput(
59
- parsePhoneNumberWithError(input, numberHasCountry ?? currCountry ?? void 0)
79
+ parsePhoneNumberWithError(input, useCountry ?? void 0)
60
80
  );
61
81
  } catch (err) {
62
82
  if (err instanceof ParseError) {
@@ -71,10 +91,31 @@ const handleParsePhoneNumber = (rawInput, currCountry = null) => {
71
91
  }
72
92
  const formatOption = combinedOptions.format === "national" ? "nationalNumber" : "e164";
73
93
  const formattedValue = combinedOptions.format === "national" ? "formatOriginal" : "formatInternational";
94
+ const initialCursorPosition = el?.selectionStart || 0;
74
95
  if (combinedOptions.spaces && detailedValue?.[formattedValue]) {
75
96
  inputValue = detailedValue[formattedValue] ?? null;
97
+ await tick();
98
+ if (el) {
99
+ const newCursorPosition = findNewCursorPosition(
100
+ input,
101
+ inputValue,
102
+ initialCursorPosition
103
+ );
104
+ el.selectionStart = newCursorPosition;
105
+ el.selectionEnd = newCursorPosition;
106
+ }
76
107
  } else if (detailedValue?.[formatOption]) {
77
108
  inputValue = detailedValue[formatOption] ?? null;
109
+ await tick();
110
+ if (el) {
111
+ const newCursorPosition = findNewCursorPosition(
112
+ input,
113
+ inputValue,
114
+ initialCursorPosition
115
+ );
116
+ el.selectionStart = newCursorPosition;
117
+ el.selectionEnd = newCursorPosition;
118
+ }
78
119
  }
79
120
  value = detailedValue?.e164 ?? input ?? null;
80
121
  valid = detailedValue?.isValid ?? false;
@@ -124,13 +165,16 @@ export const updateValue = (newValue, newCountry) => {
124
165
  if (castedValue) {
125
166
  handleParsePhoneNumber(
126
167
  castedValue,
127
- getCountryForPartialE164Number(castedValue) || newCountry
168
+ options?.strictCountry ? country : getCountryForPartialE164Number(castedValue) || newCountry
128
169
  );
129
170
  }
130
171
  };
131
172
  onMount(() => {
132
173
  if (value) {
133
- handleParsePhoneNumber(value, getCountryForPartialE164Number(value) || country);
174
+ handleParsePhoneNumber(
175
+ value,
176
+ options?.strictCountry ? country : getCountryForPartialE164Number(value) || country
177
+ );
134
178
  }
135
179
  });
136
180
  </script>
@@ -162,6 +206,7 @@ onMount(() => {
162
206
  use:telInputAction={{
163
207
  handler: handleInputAction,
164
208
  spaces: combinedOptions.spaces,
165
- value
209
+ value,
210
+ strictCountryCode: combinedOptions.strictCountry
166
211
  }}
167
212
  />
@@ -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.2",
4
+ "version": "3.6.1",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/gyurielf/svelte-tel-input.git"