svelte-tel-input 1.3.2 → 2.0.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/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # svelte-tel-input
2
2
 
3
+ ## 2.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - breaking: switch from default to named export to export TelInput component. Use named import in the future. From now Svelte >= 3.58.0 is required. ([#143](https://github.com/gyurielf/svelte-tel-input/pull/143))
8
+
9
+ ### Minor Changes
10
+
11
+ - feat: space config option added, it will enable or disable spaces in the input field. ([#143](https://github.com/gyurielf/svelte-tel-input/pull/143))
12
+
13
+ - feat: autoPlaceholder feature added, it generates placeholder for each country. ([#143](https://github.com/gyurielf/svelte-tel-input/pull/143))
14
+
15
+ ### Patch Changes
16
+
17
+ - chore: update deps, re-generate package-lock.json ([#143](https://github.com/gyurielf/svelte-tel-input/pull/143))
18
+
19
+ - feat: added options panel to example page to be able to try out config opts. ([#143](https://github.com/gyurielf/svelte-tel-input/pull/143))
20
+
3
21
  ## 1.3.2
4
22
 
5
23
  ### Patch Changes
package/README.md CHANGED
@@ -6,15 +6,6 @@
6
6
 
7
7
  > Lightweight svelte tel/phone input standardizer.
8
8
 
9
- The package is recently bumped to `1.0`. If you experience any problems, please open an issue, to be able to me to fix it.
10
-
11
- ## Goals
12
-
13
- - Solve the problem that a users can enter the same phone number in different formats.
14
- - Storing a phone number in a standard format, that can be indexable and searchable in any database.
15
- - Should be accessible for the the browser. Eg. for a `<a href="tel+36201234567 />`.
16
- - The stored phone number format can be useable for any SMS gateway(e.g for 2FA) and if somebody can call the number from anywhere, it should work.
17
-
18
9
  ## Installation
19
10
 
20
11
  Svelte Tel Input is distributed via [npm](https://www.npmjs.com/package/svelte-tel-input).
@@ -27,9 +18,9 @@ npm install --save svelte-tel-input
27
18
 
28
19
  - Parse and validate phone number.You can store one exact format (`E164`), no matter how users type their phone numbers.
29
20
  - Format (specified to its country), to make it more readable.
30
- - Optionally it can set the user's current country automatically, via IP lookup.
31
- - Prevent non-digits typing into the input, except the `+` sign (and `space` optionally).
32
- - Handle copy-pasted phone numbers, it's sanitize non-digit characters except the `+` sign (and `space` optionally).
21
+ - Prevent non-digits typing into the input, except the leading `+` sign (and `space` optionally).
22
+ - Handle copy-pasted phone numbers, it's sanitize non-digit characters except the leading `+` sign (and `space` optionally).
23
+ - Automatic placeholder generation for the selected country.
33
24
 
34
25
  ## Usage
35
26
 
@@ -39,7 +30,7 @@ npm install --save svelte-tel-input
39
30
 
40
31
  ```html
41
32
  <script lang="ts">
42
- import TelInput, { normalizedCountries } from 'svelte-tel-input';
33
+ import { TelInput, normalizedCountries } from 'svelte-tel-input';
43
34
  import type { NormalizedTelNumber, CountryCode, E164Number } from 'svelte-tel-input/types';
44
35
 
45
36
  // Any Country Code Alpha-2 (ISO 3166)
@@ -107,17 +98,26 @@ npm install --save svelte-tel-input
107
98
 
108
99
  The default export of the library is the main TelInput component. It has the following props:
109
100
 
110
- | Props | Type | Default Value | Usage |
111
- | -------------- | --------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
112
- | country | `CountryCode \| null` | `null` | It's accept any Country Code Alpha-2 (ISO 3166). You can set manually (e.g: by the user via a select). The parser will inspect the entered phone number and if it detect a valid country calling code, then it's automatically set the country to according to the detected country calling code. E.g: `+36` -> `HU` |
113
- | disabled | `boolean` | `false` | It's block the parser and prevent entering input. You must handle its styling on your own. |
114
- | valid | `boolean` | `true` | Indicates whether the entered tel number validity. |
115
- | value | `E164Number \| null` | `null` | [E164](https://en.wikipedia.org/wiki/E.164) is the international format of phone.numbers. This is the main entry point to store and/or load an existent phone number. |
116
- | parsedTelInput | `NormalizedTelInput \|null` | `null` | All of the formatted results of the tel input. |
117
- | class | `string` | `` | You can pass down any classname to the component |
101
+ | Props | Type | Default Value | Usage |
102
+ | --------------- | --------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
103
+ | country | `CountryCode \| null` | `null` | It's accept any Country Code Alpha-2 (ISO 3166). You can set manually (e.g: by the user via a select). The parser will inspect the entered phone number and if it detect a valid country calling code, then it's automatically set the country to according to the detected country calling code. E.g: `+36` -> `HU` |
104
+ | disabled | `boolean` | `false` | It's block the parser and prevent entering input. You must handle its styling on your own. |
105
+ | valid | `boolean` | `true` | Indicates whether the entered tel number validity. |
106
+ | value | `E164Number \| null` | `null` | [E164](https://en.wikipedia.org/wiki/E.164) is the international format of phone.numbers. This is the main entry point to store and/or load an existent phone number. |
107
+ | parsedTelInput | `NormalizedTelInput \|null` | `null` | All of the formatted results of the tel input. |
108
+ | class | `string` | `` | You can pass down any classname to the component |
109
+ | autoPlaceholder | `boolean` | `true` | Generates country specific placeholder for the selected country.something |
110
+ | allowSpaces | `boolean` | `true` | Allow or disallow spaces in the input field |
118
111
 
119
112
  <p align="right">(<a href="#readme-top">back to top</a>)</p>
120
113
 
114
+ ## Goals
115
+
116
+ - Solve the problem that a users can enter the same phone number in different formats.
117
+ - Storing a phone number in a standard format, that can be indexable and searchable in any database.
118
+ - Should be accessible for the the browser. Eg. for a `<a href="tel+36201234567 />`.
119
+ - The stored phone number format can be useable for any SMS gateway(e.g for 2FA) and if somebody can call the number from anywhere, it should work.
120
+
121
121
  ## Dependencies
122
122
 
123
123
  [svelte](https://svelte.dev/)
@@ -141,7 +141,8 @@ The default export of the library is the main TelInput component. It has the fol
141
141
  - [x] Integrate libphonenumber
142
142
  - [x] Implement parser
143
143
  - [x] Add basics docs and examples
144
- - [ ] Add advanced examples
144
+ - [x] Add advanced examples
145
+ - [x] Generate placeholders autimatically
145
146
  - [ ] Improve A11Y
146
147
 
147
148
  See the [open issues](https://github.com/gyurielf/svelte-tel-input/issues) for a list of proposed features (and known issues).
@@ -119,7 +119,7 @@ const onChange = (selectedCountry) => {
119
119
  <button
120
120
  value={country.iso2}
121
121
  type="button"
122
- class="inline-flex py-2 px-4 w-full text-sm hover:bg-gray-100 dark:hover:bg-gray-600
122
+ class="inline-flex py-2 px-4 w-full text-sm hover:bg-gray-100 dark:hover:bg-gray-600
123
123
  active:bg-gray-800 dark:active:bg-gray-800 overflow-hidden
124
124
  {isActive
125
125
  ? 'bg-gray-600 dark:text-white'
@@ -1,16 +1,32 @@
1
1
  <script>import { createEventDispatcher, onMount } from "svelte";
2
2
  import { parsePhoneNumberWithError, ParseError } from "libphonenumber-js/max";
3
3
  import { telInputAction } from "../../utils/directives/telInputAction";
4
- import { normalizeTelInput, getCountryForPartialE164Number } from "../../utils/helpers";
4
+ import {
5
+ normalizeTelInput,
6
+ getCountryForPartialE164Number,
7
+ generatePlaceholder
8
+ } from "../../utils/helpers";
5
9
  import { watcher } from "../../stores";
10
+ const defaultOptions = {
11
+ autoPlaceholder: true,
12
+ spaces: true
13
+ };
6
14
  const dispatch = createEventDispatcher();
7
15
  export let country;
8
16
  export let value;
9
17
  export let parsedTelInput = null;
10
18
  export let valid = true;
11
19
  export let disabled = false;
20
+ export let placeholder = null;
21
+ export let options = defaultOptions;
22
+ export let required = null;
12
23
  let inputValue = value;
13
24
  let prevCountry = country;
25
+ $:
26
+ combinedOptions = {
27
+ ...defaultOptions,
28
+ ...options
29
+ };
14
30
  const handleInputAction = (value2) => {
15
31
  if (disabled)
16
32
  return;
@@ -42,11 +58,16 @@ const handleParsePhoneNumber = (input, currCountry = null) => {
42
58
  throw err;
43
59
  }
44
60
  }
45
- if (parsedTelInput?.isValid && parsedTelInput?.formatOriginal) {
61
+ if (parsedTelInput?.isValid && combinedOptions.spaces && parsedTelInput?.formatOriginal) {
46
62
  if (inputValue === parsedTelInput?.formatOriginal) {
47
63
  inputValue = null;
48
64
  }
49
65
  inputValue = parsedTelInput?.formatOriginal;
66
+ } else if (parsedTelInput?.isValid && parsedTelInput?.nationalNumber) {
67
+ if (inputValue === parsedTelInput?.nationalNumber) {
68
+ inputValue = null;
69
+ }
70
+ inputValue = parsedTelInput?.nationalNumber;
50
71
  }
51
72
  value = parsedTelInput?.e164 ?? null;
52
73
  valid = parsedTelInput?.isValid ?? false;
@@ -90,9 +111,13 @@ const watchFunction = () => {
90
111
  const countryChangeWatch = watcher(null, watchFunction);
91
112
  $:
92
113
  $countryChangeWatch = country;
114
+ $:
115
+ getPlaceholder = combinedOptions.autoPlaceholder ? country ? generatePlaceholder(country) : null : placeholder;
93
116
  </script>
94
117
 
95
118
  <input
119
+ {required}
120
+ placeholder={getPlaceholder}
96
121
  {disabled}
97
122
  type="tel"
98
123
  value={inputValue}
@@ -107,5 +132,5 @@ $:
107
132
  on:keypress
108
133
  on:keyup
109
134
  on:paste
110
- use:telInputAction={handleInputAction}
135
+ use:telInputAction={{ handler: handleInputAction, spaces: combinedOptions.spaces }}
111
136
  />
@@ -1,5 +1,5 @@
1
1
  import { SvelteComponentTyped } from "svelte";
2
- import type { NormalizedTelNumber, CountryCode, E164Number } from '../../types';
2
+ import type { NormalizedTelNumber, CountryCode, E164Number, TelInputOptions } from '../../types';
3
3
  declare const __propDef: {
4
4
  props: {
5
5
  [x: string]: any;
@@ -8,6 +8,9 @@ declare const __propDef: {
8
8
  parsedTelInput?: Partial<NormalizedTelNumber> | null | undefined;
9
9
  valid?: boolean | undefined;
10
10
  disabled?: boolean | undefined;
11
+ placeholder?: string | null | undefined;
12
+ options?: TelInputOptions | undefined;
13
+ required?: boolean | null | undefined;
11
14
  };
12
15
  events: {
13
16
  beforeinput: InputEvent;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "svelte-tel-input",
3
3
  "description": "svelte-tel-input",
4
- "version": "1.3.2",
4
+ "version": "2.0.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/gyurielf/svelte-tel-input.git"
@@ -16,49 +16,49 @@
16
16
  "intl tel input"
17
17
  ],
18
18
  "engines": {
19
- "npm": ">= 7",
19
+ "npm": ">= 8",
20
20
  "yarn": ">=2",
21
21
  "node": ">= 16",
22
22
  "pnpm": ">= 7"
23
23
  },
24
24
  "dependencies": {
25
- "libphonenumber-js": "^1.10.21",
26
- "svelte": "^3.55.1"
25
+ "libphonenumber-js": "^1.10.28",
26
+ "svelte": "^3.58.0"
27
27
  },
28
28
  "devDependencies": {
29
- "@changesets/cli": "^2.26.0",
29
+ "@changesets/cli": "^2.26.1",
30
30
  "@changesets/get-github-info": "^0.5.2",
31
31
  "@changesets/types": "^5.2.1",
32
32
  "@macfja/svelte-persistent-store": "^2.2.1",
33
- "@playwright/test": "^1.31.2",
34
- "@sveltejs/adapter-static": "^2.0.1",
35
- "@sveltejs/kit": "^1.11.0",
33
+ "@playwright/test": "^1.32.3",
34
+ "@sveltejs/adapter-static": "^2.0.2",
35
+ "@sveltejs/kit": "^1.15.7",
36
36
  "@sveltejs/package": "^1.0.2",
37
37
  "@testing-library/svelte": "^3.2.2",
38
38
  "@testing-library/user-event": "^14.4.3",
39
- "@typescript-eslint/eslint-plugin": "^5.54.1",
40
- "@typescript-eslint/parser": "^5.54.1",
41
- "autoprefixer": "^10.4.13",
42
- "cssnano": "^5.1.15",
39
+ "@typescript-eslint/eslint-plugin": "^5.59.0",
40
+ "@typescript-eslint/parser": "^5.59.0",
41
+ "autoprefixer": "^10.4.14",
42
+ "cssnano": "^6.0.0",
43
43
  "dotenv": "^16.0.3",
44
- "edit-package-json": "^0.8.9",
45
- "eslint": "^8.35.0",
46
- "eslint-config-prettier": "^8.7.0",
44
+ "edit-package-json": "^0.8.12",
45
+ "eslint": "^8.39.0",
46
+ "eslint-config-prettier": "^8.8.0",
47
47
  "eslint-plugin-svelte3": "^4.0.0",
48
48
  "husky": "^8.0.3",
49
- "jsdom": "^21.1.0",
49
+ "jsdom": "^21.1.1",
50
50
  "micromatch": "^4.0.5",
51
- "postcss": "^8.4.21",
52
- "prettier": "^2.8.4",
53
- "prettier-plugin-svelte": "^2.9.0",
51
+ "postcss": "^8.4.23",
52
+ "prettier": "^2.8.7",
53
+ "prettier-plugin-svelte": "^2.10.0",
54
54
  "schema-dts": "^1.1.2",
55
- "svelte-check": "^3.1.0",
56
- "svelte2tsx": "^0.6.3",
57
- "tailwindcss": "^3.2.7",
55
+ "svelte-check": "^3.2.0",
56
+ "svelte2tsx": "^0.6.11",
57
+ "tailwindcss": "^3.3.1",
58
58
  "tslib": "^2.5.0",
59
- "typescript": "^4.9.5",
60
- "vite": "^4.1.4",
61
- "vitest": "^0.29.2"
59
+ "typescript": "^5.0.4",
60
+ "vite": "^4.3.1",
61
+ "vitest": "^0.30.1"
62
62
  },
63
63
  "type": "module",
64
64
  "license": "MIT",
package/types/index.d.ts CHANGED
@@ -41,7 +41,7 @@ export interface NormalizedTelNumber {
41
41
  countryCallingCode: CountryCallingCode | null;
42
42
  formattedNumber: string | null;
43
43
  formatOriginal: string | null;
44
- nationalNumber: NationalNumber | null;
44
+ nationalNumber: string | null;
45
45
  formatInternational: string | null;
46
46
  formatNational: string | null;
47
47
  uri: string | null;
@@ -74,3 +74,25 @@ export type TelInputDispatchEvents = {
74
74
  valid: boolean;
75
75
  value: E164Number | null;
76
76
  };
77
+
78
+ export interface TelInputOptions {
79
+ /**
80
+ * It generates a placeholder into your input for the selected country. E.g. if the country is `US`, the placeholder will be `201 555 0123` by default.
81
+ * If you need other format, you can use tha `national` -> `(201) 555-0123` and `international` -> `+1 201 555 0123` mode.
82
+ * @default true
83
+ */
84
+
85
+ autoPlaceholder?: boolean;
86
+ /**
87
+ * Allow or disallow spaces in the input field
88
+ * @default true
89
+ */
90
+ spaces?: boolean;
91
+ /**
92
+ * "formatInternational": "+36 20 123 4567",
93
+ * "formatOriginal": "20 123 4567",
94
+ * "formatNational": "06 20 123 4567",
95
+ * @default 'original'
96
+ */
97
+ // format: 'original' | 'national' | 'international';
98
+ }
@@ -1,3 +1,6 @@
1
- export declare const telInputAction: (node: HTMLInputElement, handler: (val: string) => void) => {
1
+ export declare const telInputAction: (node: HTMLInputElement, { handler, spaces }: {
2
+ handler: (val: string) => void;
3
+ spaces: boolean;
4
+ }) => {
2
5
  destroy(): void;
3
6
  };
@@ -1,11 +1,11 @@
1
1
  import { inspectAllowedChars, inputParser } from '../..';
2
- export const telInputAction = (node, handler) => {
2
+ export const telInputAction = (node, { handler, spaces }) => {
3
3
  const onInput = (event) => {
4
4
  if (node && node.contains(event.target)) {
5
5
  const value = event.target.value;
6
6
  const formattedInput = inputParser(value, {
7
7
  parseCharacter: inspectAllowedChars,
8
- allowSpaces: true
8
+ allowSpaces: spaces
9
9
  });
10
10
  node.value = formattedInput;
11
11
  handler(formattedInput);
@@ -5,6 +5,7 @@ export declare const isNumber: (value: number) => boolean;
5
5
  export declare const normalizeTelInput: (input?: PhoneNumber) => {
6
6
  [k: string]: string | boolean | E164Number | import("libphonenumber-js/types").CountryCallingCode | import("libphonenumber-js/types").NationalNumber | null | undefined;
7
7
  };
8
+ export declare const generatePlaceholder: (country: CountryCode, format?: 'international' | 'national' | 'default') => string;
8
9
  export declare const isSelected: <T extends {
9
10
  id: string;
10
11
  }>(itemToSelect: string | T, selectedItem: string | T | null | undefined) => boolean;
package/utils/helpers.js CHANGED
@@ -1,4 +1,5 @@
1
- import { AsYouType, Metadata, getCountryCallingCode } from 'libphonenumber-js/max';
1
+ import { AsYouType, Metadata, getCountryCallingCode, getExampleNumber } from 'libphonenumber-js/max';
2
+ import examples from 'libphonenumber-js/mobile/examples';
2
3
  export const capitalize = (str) => {
3
4
  return (str && str[0].toUpperCase() + str.slice(1).toLowerCase()) || '';
4
5
  };
@@ -43,6 +44,26 @@ export const normalizeTelInput = (input) => {
43
44
  }).filter(([, value]) => value !== null));
44
45
  return filteredResult;
45
46
  };
47
+ export const generatePlaceholder = (country, format = 'default') => {
48
+ const examplePhoneNumber = getExampleNumber(country, examples);
49
+ if (examplePhoneNumber) {
50
+ const countryCallingCode = examplePhoneNumber.countryCallingCode;
51
+ switch (format) {
52
+ case 'international':
53
+ return examplePhoneNumber.formatInternational();
54
+ case 'national':
55
+ return examplePhoneNumber.formatNational();
56
+ default:
57
+ return examplePhoneNumber
58
+ .formatInternational()
59
+ .slice(countryCallingCode.length + 1)
60
+ .trim();
61
+ }
62
+ }
63
+ else {
64
+ throw new Error(`No country found with this country code: ${country}`);
65
+ }
66
+ };
46
67
  export const isSelected = (itemToSelect, selectedItem) => {
47
68
  if (!selectedItem || selectedItem === null) {
48
69
  return false;
@@ -199,7 +220,7 @@ export const isSupportedCountry = (country, metadata) => {
199
220
  * @returns {string}
200
221
  */
201
222
  export const allowedCharacters = (character, { spaces } = {
202
- spaces: false
223
+ spaces: true
203
224
  }) => {
204
225
  const DIGITS = {
205
226
  '0': '0',