Skip to content

Commit 5cb1cc3

Browse files
toozuuuSebGaillard1cursoragent
authored
feat: add excludeCountries, searchPlaceholder, and flag visibility controls (#90)
## PR Description ### **Description** This PR introduces several highly requested features and customization inputs to `ngxsmk-tel-input`, achieving parity and superiority over `ngx-intl-tel-input-gg`. All new configurations support both the traditional `@Input()` bindings and the modern Signal-based `input()` APIs. ### **Key Features Added** 1. **Exclude Specific Countries (`excludeCountries` / `excludeCountriesSignal`)** - Allows excluding specific ISO-2 country codes from appearing inside the dropdown list. 2. **Custom Search Placeholder (`searchPlaceholder` / `searchPlaceholderSignal`)** - Dynamically customizes the placeholder text of the country search field inside the dropdown container. 3. **Hide Flags Completely (`showFlags` / `showFlagsSignal`)** - Completely removes flag elements from both the selected input wrapper and country dropdown list for minimalist, text-only layouts. 4. **Hide Flags only in Dropdown (`searchCountryFlag` / `searchCountryFlagSignal`)** - Hides flag icons only within the search results dropdown list, keeping the flag in the selected dial code wrapper. --- ### **Files Changed** - **Core logic & mappings**: [ngxsmk-tel-input.component.ts](file:///d:/My%20Projects/ngxsmk-tel-input/projects/ngxsmk-tel-input/src/lib/ngxsmk-tel-input.component.ts) - **CSS flag-hiding rules**: [ngxsmk-tel-input.component.scss](file:///d:/My%20Projects/ngxsmk-tel-input/projects/ngxsmk-tel-input/src/lib/ngxsmk-tel-input.component.scss) - **Type enhancements**: [types-enhanced.ts](file:///d:/My%20Projects/ngxsmk-tel-input/projects/ngxsmk-tel-input/src/lib/types-enhanced.ts) - **Test coverage**: [ngxsmk-tel-input.component.spec.ts](file:///d:/My%20Projects/ngxsmk-tel-input/projects/ngxsmk-tel-input/src/lib/ngxsmk-tel-input.component.spec.ts) - **Documentation**: [CHANGELOG.md](file:///d:/My%20Projects/ngxsmk-tel-input/CHANGELOG.md), [README.md](file:///d:/My%20Projects/ngxsmk-tel-input/README.md), library [README.md](file:///d:/My%20Projects/ngxsmk-tel-input/projects/ngxsmk-tel-input/README.md), [SIGNALS_API.md](file:///d:/My%20Projects/ngxsmk-tel-input/projects/ngxsmk-tel-input/SIGNALS_API.md), and [TYPESCRIPT.md](file:///d:/My%20Projects/ngxsmk-tel-input/projects/ngxsmk-tel-input/TYPESCRIPT.md). --- ### **Verification Results** - **Automated Tests**: Unit tests added for each new input/signal combination. All 75 tests pass: ```bash npm run test:lib -- --watch=false --browsers=ChromeHeadless ``` - **Successful Compilations**: Verified that the library (`npm run build:lib`) and the demo application (`npm run build:demo`) compile cleanly without Ivy bails or warnings. --------- Co-authored-by: Sébastien Gaillard <82144644+SebGaillard1@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent aeb19da commit 5cb1cc3

32 files changed

Lines changed: 1378 additions & 1953 deletions

.github/workflows/ci.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
branches: [main, master]
6+
push:
7+
branches: [main, master]
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
library:
14+
name: Library Build and Tests
15+
runs-on: ubuntu-latest
16+
strategy:
17+
fail-fast: false
18+
matrix:
19+
node-version: [18, 20]
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v5
23+
24+
- name: Setup Node.js
25+
uses: actions/setup-node@v4
26+
with:
27+
node-version: ${{ matrix.node-version }}
28+
cache: npm
29+
30+
- name: Install dependencies
31+
run: npm ci
32+
33+
- name: Build library
34+
run: npx ng build ngxsmk-tel-input --configuration production
35+
36+
- name: Run library tests
37+
run: npx ng test ngxsmk-tel-input --watch=false --browsers=ChromeHeadless

.github/workflows/deploy-demo.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ jobs:
3535
- name: Build library
3636
run: npx ng build ngxsmk-tel-input --configuration production
3737

38+
- name: Run library tests
39+
run: npx ng test ngxsmk-tel-input --watch=false --browsers=ChromeHeadless
40+
3841
- name: Build demo
3942
run: |
4043
REPO_NAME=${GITHUB_REPOSITORY#*/}

.github/workflows/publish.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ jobs:
2121
registry-url: 'https://registry.npmjs.org'
2222

2323
- run: npm ci
24+
- run: npx ng test ngxsmk-tel-input --watch=false --browsers=ChromeHeadless
2425
- run: npx ng build ngxsmk-tel-input --configuration production
2526

2627
- name: Publish to npm (with provenance)

CHANGELOG.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10-
## [1.6.11] - 2026-05-01
10+
### Added
11+
- **excludeCountries / excludeCountriesSignal**: Exclude specific country ISO codes from appearing in the dropdown list.
12+
- **searchPlaceholder / searchPlaceholderSignal**: Customizable placeholder text for the country search input.
13+
- **showFlags / showFlagsSignal**: Hides flags completely from the selected input and country dropdown.
14+
- **searchCountryFlag / searchCountryFlagSignal**: Hides flag icons only within the dropdown list items while maintaining the selected flag display.
1115

12-
### Changed
13-
- Bumped stable/current package version references across workspace to `1.6.11`.
16+
---
1417

15-
## [1.6.10] - 2026-01-19
18+
## [1.7.0] - 2026-06-06
1619

1720
### Changed
18-
- **Dependencies**: Updated `intl-tel-input` to version 25 compatibility.
19-
- **Internal**: Migrated `preferredCountries` to `countryOrder` to support `intl-tel-input` v25.
2021
- **Example Components**: All example components (E-commerce Checkout, User Registration, Profile Management) now default to dark mode theme
2122
- **Demo App**: Default theme changed to dark mode for better visibility and consistency
2223
- **Navigation UI**: Fixed icon and text colors in dark mode navigation menu for better contrast and readability
2324

25+
### Fixed
26+
- **Invalid Country Code False Positive**: Fixed `isInvalidInternationalNumber()` incorrectly flagging valid international numbers whose country code starts with a single-digit prefix that is itself not a country code (e.g. Greece `+30`, France `+33`, Germany `+49`, Australia `+61`, India `+91`). The loop now continues through all 1–3 digit prefix candidates and only flags a number as invalid if none of them produce a valid parse, rather than short-circuiting on the first failure. Non-`+` prefixed (national-format) inputs are also no longer passed through the loop at all.
27+
2428
## [1.6.9] - 2025-01-21
2529

2630
### Added

CONTRIBUTING.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ By participating in this project, you are expected to uphold the project's goals
66

77
---
88

9-
## How to Contribute
9+
## How to Contribute
1010

1111
There are several ways you can help improve this project:
1212

1313
1. **Report Bugs:** Submit an issue if you find a problem.
1414
2. **Suggest Features:** Open an issue to propose new functionality.
1515
3. **Contribute Code:** Submit a Pull Request with bug fixes or new features.
1616

17-
## Reporting Bugs
17+
## Reporting Bugs
1818

1919
If you find a bug, please check the [Issues page](https://github.com/toozuuu/ngxsmk-tel-input/issues) to see if it has already been reported.
2020

@@ -24,13 +24,13 @@ When submitting a new bug report, please include:
2424
* Your **Angular version** and the **browser** you are using.
2525
* A minimal reproduction link (e.g., CodePen, JSFiddle) if possible.
2626

27-
## Suggesting Enhancements
27+
## Suggesting Enhancements
2828

2929
If you have an idea for a new feature or an enhancement, please open a new issue on the [Issues page](https://github.com/toozuuu/ngxsmk-tel-input/issues).
3030

3131
Describe the feature, why you think it would be useful, and how it aligns with the goals of the library.
3232

33-
## Code Contributions (Pull Requests)
33+
## Code Contributions (Pull Requests)
3434

3535
We welcome pull requests for bug fixes and new features.
3636

README.md

Lines changed: 40 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,57 @@
11
# ngxsmk-tel-input
22

3-
An Angular **phone input / telephone input** component with country dropdown, flags, international formatting, and robust validation.
4-
Built on top of [`intl-tel-input`](https://github.com/jackocnr/intl-tel-input) + [`libphonenumber-js`](https://github.com/catamphetamine/libphonenumber-js), and fully compatible with Angular Reactive Forms and template-driven forms through `ControlValueAccessor`.
3+
An Angular **telephone input** component with country dropdown, flags, and robust validation/formatting.
4+
Wraps [`intl-tel-input`](https://github.com/jackocnr/intl-tel-input) for the UI and [`libphonenumber-js`](https://github.com/catamphetamine/libphonenumber-js) for parsing/validation. Implements `ControlValueAccessor` so it plugs into Angular Forms.
55

66
> Emits **E.164** by default (e.g. `+14155550123`). SSR‑safe via lazy browser‑only import.
77
8-
## Try it live on StackBlitz
8+
## Try it live on StackBlitz
99

1010
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/~/github.com/toozuuu/ngxsmk-tel-input)
1111

1212
---
1313

14-
## Features
14+
## Features
1515

1616
* Country dropdown with flags
17-
* E.164 output (display can be national with `nationalMode`)
17+
* E.164 output (display can be configured via `nationalDisplay`)
1818
* Reactive & template‑driven Forms support (CVA)
1919
* Built‑in validation using libphonenumber‑js
2020
* **Enhanced validation**: Detects invalid country codes (like "11", "99") and shows appropriate error states
2121
* **Mobile responsive**: Optimized for touch devices with proper tap targets, prevents iOS zoom, and responsive dropdown
22-
* **Dark & Light themes**: Improved dark-mode contrast, consistent code/readout colors, and automatic system preference detection
22+
* **Dark & Light themes**: Comprehensive theme system with automatic system preference detection
2323
* **Accessibility**: Full ARIA support, screen reader compatibility, keyboard navigation
24+
* **Integrations & Ionic ready**: Built-in support for Twilio, Vonage, AWS SNS, and Ionic Framework overlays/themes (see [INTEGRATIONS.md](./projects/ngxsmk-tel-input/INTEGRATIONS.md))
2425
* SSR‑friendly (no `window` on the server)
2526
* Easy theming via CSS variables
2627
* Nice UX options: label/hint/error text, sizes, variants, clear button, autofocus, select-on-focus
2728
* Masking & caret-friendly as-you-type formatting (optional)
2829
* Format only when valid (formatWhenValid) and lock once valid (lockWhenValid) to prevent extra digits
2930

30-
### Demo app highlights
31-
32-
The workspace demo (`ng serve demo`) now includes:
33-
34-
* polished documentation-style layout with improved spacing and visual hierarchy
35-
* responsive sidebar/header behavior for mobile and desktop
36-
* cleaner dark-mode palette with better text/background contrast
37-
* improved focus states and reduced-motion support for accessibility
38-
3931
---
4032

41-
## Requirements
33+
## Requirements
4234

43-
* Angular **17+** (17, 18, 19, 20, 21+)
35+
* Angular **17+** (actively tested on Angular 19)
4436
* Node **18** or **20**
4537

46-
> Library `peerDependencies` target Angular `>=17`. Fully compatible with Angular 17, 18, 19, 20, 21, and future versions.
38+
> Library `peerDependencies` target Angular `>=17`.
4739
48-
### Zone.js Compatibility
40+
### Zone.js Compatibility
4941

5042
This component works seamlessly with **both Zone.js and zoneless Angular**:
5143

52-
* **With Zone.js** (traditional Angular): Full compatibility
53-
* **Without Zone.js** (Angular 18+ zoneless): Full compatibility
54-
* **All data binding types**: Property bindings, event bindings, two-way bindings
55-
* **Reactive Forms & Template-driven Forms**: Full support
56-
* **Signals**: Compatible with Angular signals (Angular 16+)
44+
* **With Zone.js** (traditional Angular): Full compatibility
45+
* **Without Zone.js** (Angular 18+ zoneless): Full compatibility
46+
* **All data binding types**: Property bindings, event bindings, two-way bindings
47+
* **Reactive Forms & Template-driven Forms**: Full support
48+
* **Signals**: Compatible with Angular signals (Angular 16+)
5749

5850
The component automatically detects whether Zone.js is available and adapts its change detection strategy accordingly.
5951

6052
---
6153

62-
## Install
54+
## Install
6355

6456
```bash
6557
npm i ngxsmk-tel-input intl-tel-input libphonenumber-js
@@ -119,7 +111,7 @@ Ensure your app includes a proper viewport meta tag:
119111

120112
---
121113

122-
## Quick start (Reactive Forms)
114+
## Quick start (Reactive Forms)
123115

124116
```ts
125117
// app.component.ts
@@ -180,7 +172,7 @@ export class AppComponent {
180172

181173
---
182174

183-
## Template‑driven usage
175+
## Template‑driven usage
184176

185177
```html
186178
<form #f="ngForm">
@@ -191,7 +183,7 @@ export class AppComponent {
191183

192184
---
193185

194-
## Localization & RTL
186+
## Localization & RTL
195187

196188
You can localize the dropdown/search labels and override country names.
197189

@@ -241,19 +233,23 @@ Arabic + RTL example
241233
```
242234

243235

244-
## API
236+
## API
245237

246238
### Inputs
247239

248240
| Name | Type | Default | Description |
249241
|------------------------|---------------------------------------------|-------------------------|--------------------------------------------------------------------------------------------|
250-
| `initialCountry` | `CountryCode \| 'auto'` | `'US'` | Starting country. `'auto'` uses geoIp stub (`US` by default). |
242+
| `initialCountry` | `CountryCode \| 'auto'` | `'US'` | Starting country (also respected when initial form value is `''`). `'auto'` uses geoIp stub (`US` by default). |
251243
| `preferredCountries` | `CountryCode[]` | `['US','GB']` | Pin these at the top. |
252244
| `onlyCountries` | `CountryCode[]` || Limit selectable countries. |
253-
| `nationalMode` | `boolean` | `false` | If `true`, **display** national format in the input. Value still emits E.164. |
254-
| `separateDialCode` | `boolean` | `false` | Show dial code outside the input. |
245+
| `excludeCountries` | `CountryCode[]` | `[]` | Exclude specific countries from the dropdown list. |
246+
| `searchPlaceholder` | `string` | `''` | Custom placeholder text for the dropdown search input. |
247+
| `showFlags` | `boolean` | `true` | Hide flags completely for minimalist/text-only layouts. |
248+
| `searchCountryFlag` | `boolean` | `true` | Hide flag icons inside the country dropdown list. |
249+
| `nationalDisplay` | `'formatted' \| 'digits'` | `'formatted'` | Controls visible input format. Value still emits E.164. |
250+
| `separateDialCode` | `boolean` | `true` | Show dial code outside the input. |
255251
| `allowDropdown` | `boolean` | `true` | Enable/disable dropdown. |
256-
| `placeholder` | `string` | `'Enter phone number'` | Input placeholder. |
252+
| `placeholder` | `string` | | Input placeholder. |
257253
| `autocomplete` | `string` | `'tel'` | Native autocomplete. |
258254
| `disabled` | `boolean` | `false` | Disable the control. |
259255
| `label` | `string` || Optional floating label text. |
@@ -264,14 +260,14 @@ Arabic + RTL example
264260
| `showClear` | `boolean` | `true` | Show a clear (×) button when not empty. |
265261
| `autoFocus` | `boolean` | `false` | Focus on init. |
266262
| `selectOnFocus` | `boolean` | `false` | Select all text on focus. |
267-
| `formatOnBlur` | `boolean` | `true` | Pretty‑print on blur (national if `nationalMode`). |
263+
| `formatWhenValid` | `'off' \| 'blur' \| 'typing'` | `'typing'` | When to format the display value. |
268264
| `showErrorWhenTouched` | `boolean` | `true` | Show error styles only after blur. |
269265
| `dropdownAttachToBody` | `boolean` | `true` | Attach dropdown to `<body>` (avoids clipping/overflow). |
270266
| `dropdownZIndex` | `number` | `2000` | Z‑index for dropdown panel. |
271267
| `i18n` | `IntlTelI18n` || Localize dropdown/search/ARIA labels. |
272268
| `localizedCountries` | `Partial<Record<CountryCode, string>>` || Override country display names (ISO-2 keys). |
273269
| `dir` | `'ltr' \| 'rtl'` | `'ltr'` | Text direction for the control. |
274-
| `autoPlaceholder` | `'off' \| 'polite' \| 'aggressive'` | `'polite'` | Example placeholders. Requires `utilsScript` unless `off`. |
270+
| `autoPlaceholder` | `'off' \| 'polite' \| 'aggressive'` | `'off'` | Example placeholders. Requires `utilsScript` unless `off`. |
275271
| `utilsScript` | `string` || Path/URL to `utils.js` (needed for example placeholders). |
276272
| `customPlaceholder` | `(example: string, country: any) => string` || Transform the example placeholder. |
277273
| `clearAriaLabel` | `string` | `'Clear phone number'` | ARIA label for the clear button. |
@@ -287,18 +283,15 @@ Arabic + RTL example
287283
| `countryChange` | `{ iso2: CountryCode }` | Fired when selected country changes. |
288284
| `validityChange` | `boolean` | Fired when validity flips. |
289285
| `inputChange` | `{ raw: string; e164: string \| null; iso2: CountryCode }` | Emitted on every keystroke. |
290-
| `ready` | `void` | Emitted after plugin + listeners finish wiring (including each re-init cycle). |
291286

292287
### Public methods
293288

294289
* `focus(): void`
295290
* `selectCountry(iso2: CountryCode): void`
296291

297-
For deterministic first render behavior, prefer setting `[initialCountry]` directly. If you call imperative APIs like `selectCountry(...)` immediately after mount, wait for `(ready)` first.
298-
299292
---
300293

301-
## Formatting & validity behavior
294+
## Formatting & validity behavior
302295

303296
* No formatting while invalid. As-you-type masking only starts when the digits form a valid number for the selected country.
304297

@@ -311,7 +304,7 @@ For rare patterns not covered by libphonenumber-js, the control falls back to ra
311304
---
312305

313306

314-
## Theming
307+
## Theming
315308

316309
### CSS Variables
317310

@@ -365,7 +358,7 @@ Dark mode: wrap in a `.dark` parent or use `[theme]="'dark'"` — tokens adapt a
365358

366359
---
367360

368-
## Validation patterns
361+
## Validation patterns
369362

370363
```html
371364
<ngxsmk-tel-input formControlName="phone"></ngxsmk-tel-input>
@@ -401,14 +394,14 @@ The component now includes enhanced validation that detects and handles various
401394
402395
---
403396

404-
## SSR notes
397+
## SSR notes
405398

406399
* The library lazy‑imports `intl-tel-input` only in the **browser** (guards with `isPlatformBrowser`).
407400
* No `window`/`document` usage on the server path.
408401

409402
---
410403

411-
## Local development
404+
## Local development
412405

413406
This repo is an Angular workspace with a library.
414407

@@ -429,7 +422,7 @@ npm i ../path-to-workspace/dist/ngxsmk-tel-input/ngxsmk-tel-input-<version>.tgz
429422
430423
---
431424

432-
## Troubleshooting
425+
## Troubleshooting
433426

434427
**UI looks unstyled / bullets in dropdown**
435428
Add the CSS and assets in `angular.json` (see Install). Restart the dev server.
@@ -448,13 +441,13 @@ Clear `.angular/cache`, rebuild the lib, and restart `ng serve`.
448441

449442
---
450443

451-
## License
444+
## License
452445

453446
[MIT](./LICENSE)
454447

455-
## Credits
448+
## Credits
456449

457450
* UI powered by [`intl-tel-input`](https://github.com/jackocnr/intl-tel-input)
458451
* Parsing & validation by [`libphonenumber-js`](https://github.com/catamphetamine/libphonenumber-js)
459452

460-
Last updated: 2026-05-01
453+
Last updated: 2025-01-21

SECURITY.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ Only the **latest version published on npm** is currently supported for security
1212

1313
| Version on npm | Security Fixes |
1414
|-----------------------|----------------|
15-
| latest (most recent) | Supported |
16-
| anything older | Unsupported |
15+
| latest (most recent) | Supported |
16+
| anything older | Unsupported |
1717

1818
**Note:** The library declares Angular peer deps `>=17 <20`. Using unsupported Angular versions may limit our ability to fix or reproduce issues.
1919

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)