@kilamaelie/react-geo-picker 1.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.
Files changed (3) hide show
  1. package/LICENSE +12 -0
  2. package/README.md +214 -0
  3. package/package.json +73 -0
package/LICENSE ADDED
@@ -0,0 +1,12 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kilama Elie
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above and disclaimer notices shall be included in all copies or substantial portions of the Software.
package/README.md ADDED
@@ -0,0 +1,214 @@
1
+ # react-geo-picker 🌍
2
+
3
+ [![NPM version](https://img.shields.io/npm/v/react-geo-picker.svg?style=flat-square)](https://npmjs.org/package/react-geo-picker) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](https://opensource.org/licenses/MIT) [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue?style=flat-square&logo=typescript)](https://www.typescriptlang.org/) [![Tailwind CSS](https://img.shields.io/badge/Tailwind-CSS-38B2AC?style=flat-square&logo=tailwind-css)](https://tailwindcss.com/)
4
+
5
+ A lightweight, fully responsive, and accessible React package containing modal components and utilities for selecting **Countries**, **Cities**, and **Phone Number Calling Codes**.
6
+
7
+ Built from the ground up with **TypeScript**, **Tailwind CSS**, and **Radix UI**, `react-geo-picker` works seamlessly out-of-the-box in both **Vite (Client SPAs)** and **Next.js (App & Pages Routers, Server/Client components)**.
8
+
9
+ ---
10
+
11
+ ## ✨ Features
12
+
13
+ - 🚀 **Zero Configuration UI:** Clean, modern modals styled consistently with Tailwind CSS and Radix primitives.
14
+ - 📱 **Mobile First & Responsive:** Fluid viewports (`95vw`, optimized heights) ensuring no layout clipping on mobile devices or small screens.
15
+ - 🔄 **Framework Agnostic:** Compatible with modern React frameworks supporting `"use client"` directives natively.
16
+ - 🛠 **TypeScript First:** Fully typed out of the box with strict generics, making form integration (like `react-hook-form`) seamless.
17
+ - 📦 **Rich Built-In Datasets:** Pre-bundled with comprehensive international country profiles, national flags, calling codes, and nested city datasets.
18
+
19
+ ---
20
+
21
+ ## 📦 Installation
22
+
23
+ Install the package via your preferred package manager:
24
+
25
+ ```bash
26
+ npm install react-geo-picker
27
+ # or
28
+ yarn add react-geo-picker
29
+ # or
30
+ pnpm add react-geo-picker
31
+ ```
32
+
33
+ ### Peer & Host Dependencies
34
+ Ensure your host application has the following installed:
35
+ * `react` (^18.0.0 || ^19.0.0)
36
+ * `react-dom` (^18.0.0 || ^19.0.0)
37
+ * `tailwindcss` (configured in your project)
38
+ * `lucide-react` (used for UI icons)
39
+
40
+ ---
41
+
42
+ ## 🚀 Usage Guide
43
+
44
+ ### 1. Country Selection Modal
45
+ Allows users to pick a country name from an alphabetized, scrollable list complete with emoji flags and international codes.
46
+
47
+ ```tsx
48
+ import { useState } from 'react';
49
+ import { CountryModal } from 'react-geo-picker';
50
+
51
+ export default function CountrySelectDemo() {
52
+ const [isOpen, setIsOpen] = useState(false);
53
+ const [selectedCountry, setSelectedCountry] = useState('');
54
+
55
+ return (
56
+ <div className="w-full max-w-sm space-y-2">
57
+ <label className="text-sm font-medium text-foreground">Country</label>
58
+ <button
59
+ type="button"
60
+ onClick={() => setIsOpen(true)}
61
+ className="w-full flex items-center justify-between px-4 py-2.5 rounded-xl border border-border bg-background text-sm shadow-sm hover:bg-muted/50 transition-colors"
62
+ >
63
+ <span>{selectedCountry || 'Select a country...'}</span>
64
+ <span className="text-xs text-muted-foreground">▼</span>
65
+ </button>
66
+
67
+ <CountryModal
68
+ showCountryModal={isOpen}
69
+ setShowCountryModal={setIsOpen}
70
+ onChange={(country) => {
71
+ setSelectedCountry(country);
72
+ console.log('Selected country:', country);
73
+ }}
74
+ />
75
+ </div>
76
+ );
77
+ }
78
+ ```
79
+
80
+ ---
81
+
82
+ ### 2. City Selection Modal (Filtered by Country)
83
+ Dynamically renders the major cities associated with the selected parent country.
84
+
85
+ ```tsx
86
+ import { useState } from 'react';
87
+ import { CitiesModal } from 'react-geo-picker';
88
+
89
+ export default function CitySelectDemo() {
90
+ const [isOpen, setIsOpen] = useState(false);
91
+ const [country] = useState('Canada'); // Can be bound to your state
92
+ const [selectedCity, setSelectedCity] = useState('');
93
+
94
+ return (
95
+ <div className="w-full max-w-sm space-y-2">
96
+ <label className="text-sm font-medium text-foreground">City ({country})</label>
97
+ <button
98
+ type="button"
99
+ onClick={() => setIsOpen(true)}
100
+ className="w-full flex items-center justify-between px-4 py-2.5 rounded-xl border border-border bg-background text-sm shadow-sm hover:bg-muted/50 transition-colors"
101
+ >
102
+ <span>{selectedCity || `Select city in ${country}...`}</span>
103
+ <span className="text-xs text-muted-foreground">▼</span>
104
+ </button>
105
+
106
+ <CitiesModal
107
+ showCitiesModal={isOpen}
108
+ setShowCitiesModal={setIsOpen}
109
+ country={country}
110
+ onChange={(city) => {
111
+ setSelectedCity(city);
112
+ }}
113
+ />
114
+ </div>
115
+ );
116
+ }
117
+ ```
118
+
119
+ ---
120
+
121
+ ### 3. Phone Number Code Modal & Input Sanitizer Utility
122
+ Perfect for onboarding flows, authentication inputs, and international telephone capture.
123
+
124
+ ```tsx
125
+ import { useState } from 'react';
126
+ import { PhoneNumberModal, formatPhoneNumber } from 'react-geo-picker';
127
+
128
+ export default function PhoneInputDemo() {
129
+ const [isOpen, setIsOpen] = useState(false);
130
+ const [countryCode, setCountryCode] = useState('+1');
131
+ const [phoneNumber, setPhoneNumber] = useState('');
132
+
133
+ return (
134
+ <div className="w-full max-w-sm space-y-2">
135
+ <label className="text-sm font-medium text-foreground">Phone Number</label>
136
+ <div className="flex gap-2">
137
+ {/* Country Code Trigger Button */}
138
+ <button
139
+ type="button"
140
+ onClick={() => setIsOpen(true)}
141
+ className="px-3 py-2.5 rounded-xl border border-border bg-background text-sm font-semibold shadow-sm hover:bg-muted/50 transition-colors flex items-center gap-1.5"
142
+ >
143
+ <span>{countryCode}</span>
144
+ <span className="text-xs text-muted-foreground">▼</span>
145
+ </button>
146
+
147
+ {/* Input field utilizing formatPhoneNumber utility */}
148
+ <input
149
+ type="tel"
150
+ value={phoneNumber}
151
+ onChange={(e) => setPhoneNumber(formatPhoneNumber(e.target.value))}
152
+ placeholder="555-0199"
153
+ className="flex-1 px-4 py-2.5 rounded-xl border border-border bg-background text-sm shadow-sm focus:outline-none focus:ring-2 focus:ring-ring"
154
+ />
155
+ </div>
156
+
157
+ <PhoneNumberModal
158
+ showPhoneNumberModal={isOpen}
159
+ setShowPhoneNumberModal={setIsOpen}
160
+ onChange={(code) => {
161
+ setCountryCode(code);
162
+ }}
163
+ />
164
+ </div>
165
+ );
166
+ }
167
+ ```
168
+
169
+ ---
170
+
171
+ ## 📚 API Reference
172
+
173
+ ### Component Props
174
+
175
+ All modal components share an identical and predictable state-handling signature:
176
+
177
+ | Prop Name | Type | Description |
178
+ | :--- | :--- | :--- |
179
+ | `show[ModalName]` | `boolean` | Controls the open/closed visibility state of the modal. |
180
+ | `setShow[ModalName]` | `React.Dispatch<React.SetStateAction<boolean>>` | State dispatcher function to update visibility. |
181
+ | `onChange` | `(value: string) => void` | Callback function triggered when an item is selected. Passes back the target value (`country.name`, `city`, or `country.code`). |
182
+ | `country` *(CitiesModal only)* | `string` | The parent country string used to filter and lookup the respective cities array. |
183
+
184
+ ### Utilities
185
+
186
+ - **`formatPhoneNumber(value: string): string`**
187
+ - Strips all non-digit characters from string input.
188
+ - Automatically bounds strings to a maximum of 15 digits conforming to international standard E.164.
189
+
190
+ ---
191
+
192
+ ## 🛠 Local Development & Contributing
193
+
194
+ 1. **Clone the repository:**
195
+ ```bash
196
+ git clone https://github.com/kilamaelie/react-geo-picker.git
197
+ cd react-geo-picker
198
+ ```
199
+
200
+ 2. **Install dependencies:**
201
+ ```bash
202
+ npm install
203
+ ```
204
+
205
+ 3. **Run build watch mode:**
206
+ ```bash
207
+ npm run dev
208
+ ```
209
+
210
+ ---
211
+
212
+ ## 📄 License
213
+
214
+ Distributed under the **MIT License**. See `LICENSE` for more information.
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@kilamaelie/react-geo-picker",
3
+ "version": "1.0.0",
4
+ "description": "Lightweight, responsive React modal components and utilities for selecting countries, cities, and country codes.",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ },
14
+ "./style.css": "./dist/index.css"
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "type": "module",
20
+ "scripts": {
21
+ "build:css": "tailwindcss -i ./src/styles.css -o ./dist/index.css --minify",
22
+ "build:js": "tsup src/index.ts --format cjs,esm --dts",
23
+ "build": "tsup",
24
+ "dev": "tsup --watch"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/kilamaelie/react-geo-picker.git"
29
+ },
30
+ "keywords": [
31
+ "react",
32
+ "typescript",
33
+ "tailwind",
34
+ "countries",
35
+ "cities",
36
+ "phone-code",
37
+ "modal",
38
+ "nextjs",
39
+ "vite"
40
+ ],
41
+ "author": "Kilama Elie",
42
+ "license": "ISC",
43
+ "bugs": {
44
+ "url": "https://github.com/kilamaelie/react-geo-picker/issues"
45
+ },
46
+ "homepage": "https://github.com/kilamaelie/react-geo-picker#readme",
47
+ "peerDependencies": {
48
+ "lucide-react": "^1.41.0",
49
+ "react": "^18.0.0 || ^19.0.0",
50
+ "react-dom": "^18.0.0 || ^19.0.0",
51
+ "tailwindcss": "^3.0.0 || ^4.0.0"
52
+ },
53
+ "devDependencies": {
54
+ "@types/react": "^19.2.18",
55
+ "@types/react-dom": "^19.2.7",
56
+ "autoprefixer": "^10.5.5",
57
+ "postcss": "^8.5.28",
58
+ "react": "^19.2.8",
59
+ "react-dom": "^19.2.8",
60
+ "tailwindcss": "^4.3.3",
61
+ "tsup": "^8.5.1",
62
+ "typescript": "^5.9.3"
63
+ },
64
+ "dependencies": {
65
+ "@radix-ui/react-dialog": "^1.1.23",
66
+ "@radix-ui/react-slot": "^1.3.3",
67
+ "class-variance-authority": "^0.7.1",
68
+ "clsx": "^2.1.1",
69
+ "radix-ui": "^1.6.7",
70
+ "react-hook-form": "^7.87.0",
71
+ "tailwind-merge": "^3.6.0"
72
+ }
73
+ }