react-country-list-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.
- package/README.md +102 -0
- package/dist/CountryList.d.ts +3 -0
- package/dist/CountryList.js +64 -0
- package/dist/CountryList.native.d.ts +3 -0
- package/dist/CountryList.native.js +60 -0
- package/dist/data/countries.json +1154 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +25 -0
- package/dist/types.d.ts +16 -0
- package/dist/types.js +2 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# react-country-list-picker
|
|
2
|
+
|
|
3
|
+
A cross-platform country list / picker component **and** country dataset
|
|
4
|
+
(name, dial code, ISO code, flag emoji) that works in both **React (web)**
|
|
5
|
+
and **React Native** — with no extra config on your end.
|
|
6
|
+
|
|
7
|
+
It ships two versions of the `CountryList` component:
|
|
8
|
+
|
|
9
|
+
- `CountryList.js` — plain HTML/CSS, used automatically in web projects (CRA, Vite, Next.js, etc.)
|
|
10
|
+
- `CountryList.native.js` — built with React Native primitives (`View`, `FlatList`, ...)
|
|
11
|
+
|
|
12
|
+
React Native's Metro bundler automatically prefers `*.native.js` files, and
|
|
13
|
+
web bundlers (Webpack/Vite) just resolve the plain `.js` file — so you import
|
|
14
|
+
from the **same path** in both platforms and get the right component.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install react-country-list-picker
|
|
20
|
+
# or
|
|
21
|
+
yarn add react-country-list-picker
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
React is a peer dependency (React Native is optional and only needed if
|
|
25
|
+
you're using it in an RN project — you already have it there).
|
|
26
|
+
|
|
27
|
+
## Usage (identical code on web and React Native)
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
import { CountryList, Country } from 'react-country-list-picker';
|
|
31
|
+
|
|
32
|
+
function MyPicker() {
|
|
33
|
+
const handleSelect = (country: Country) => {
|
|
34
|
+
console.log(country.name, country.dial_code, country.code);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
return <CountryList onSelect={handleSelect} />;
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Props
|
|
42
|
+
|
|
43
|
+
| Prop | Type | Default | Description |
|
|
44
|
+
|---------------------|-------------------------------|----------------------|-------------------------------------------|
|
|
45
|
+
| `onSelect` | `(country: Country) => void` | — | Called when a country row is tapped/clicked |
|
|
46
|
+
| `data` | `Country[]` | full built-in list | Pass a filtered/custom dataset |
|
|
47
|
+
| `searchable` | `boolean` | `true` | Show/hide the built-in search box |
|
|
48
|
+
| `searchPlaceholder` | `string` | `"Search country..."`| Placeholder for the search box |
|
|
49
|
+
|
|
50
|
+
### Using just the raw data (no UI)
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { countries } from 'react-country-list-picker';
|
|
54
|
+
|
|
55
|
+
console.log(countries[0]);
|
|
56
|
+
// { name: "Afghanistan", dial_code: "+93", code: "AF", Icon: "🇦🇫" }
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Project structure
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
country-list-picker/
|
|
63
|
+
├─ src/
|
|
64
|
+
│ ├─ data/countries.json # the dataset
|
|
65
|
+
│ ├─ CountryList.tsx # web version
|
|
66
|
+
│ ├─ CountryList.native.tsx # React Native version
|
|
67
|
+
│ ├─ types.ts
|
|
68
|
+
│ └─ index.ts # public entry point
|
|
69
|
+
├─ dist/ # compiled output (generated, published to npm)
|
|
70
|
+
├─ package.json
|
|
71
|
+
├─ tsconfig.json
|
|
72
|
+
└─ README.md
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Build
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npm install
|
|
79
|
+
npm run build # compiles src/ -> dist/ with tsc
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Publish to npm
|
|
83
|
+
|
|
84
|
+
1. Update `"name"` in `package.json` to something unique on the npm registry
|
|
85
|
+
(check availability at https://www.npmjs.com/).
|
|
86
|
+
2. Bump `"version"` following semver.
|
|
87
|
+
3. Log in and publish:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
npm login
|
|
91
|
+
npm publish --access public
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`prepublishOnly` automatically runs the build first, so `dist/` is always
|
|
95
|
+
fresh when you publish.
|
|
96
|
+
|
|
97
|
+
## Notes / next steps you may want
|
|
98
|
+
|
|
99
|
+
- Add your own logo/name/license details in `package.json`.
|
|
100
|
+
- Add a `styles` prop or theme support if you want consumers to restyle rows.
|
|
101
|
+
- Add unit tests (e.g. with Jest + React Testing Library) before publishing v1.
|
|
102
|
+
- Set up CI (GitHub Actions) to run `npm run build` on every push.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = CountryList;
|
|
7
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
|
+
const react_1 = require("react");
|
|
9
|
+
const countries_json_1 = __importDefault(require("./data/countries.json"));
|
|
10
|
+
const styles = {
|
|
11
|
+
container: {
|
|
12
|
+
width: '100%',
|
|
13
|
+
maxWidth: 360,
|
|
14
|
+
border: '1px solid #e0e0e0',
|
|
15
|
+
borderRadius: 8,
|
|
16
|
+
fontFamily: 'sans-serif',
|
|
17
|
+
overflow: 'hidden',
|
|
18
|
+
},
|
|
19
|
+
search: {
|
|
20
|
+
width: '100%',
|
|
21
|
+
boxSizing: 'border-box',
|
|
22
|
+
padding: '10px 12px',
|
|
23
|
+
border: 'none',
|
|
24
|
+
borderBottom: '1px solid #e0e0e0',
|
|
25
|
+
outline: 'none',
|
|
26
|
+
fontSize: 14,
|
|
27
|
+
},
|
|
28
|
+
list: {
|
|
29
|
+
maxHeight: 320,
|
|
30
|
+
overflowY: 'auto',
|
|
31
|
+
},
|
|
32
|
+
row: {
|
|
33
|
+
display: 'flex',
|
|
34
|
+
alignItems: 'center',
|
|
35
|
+
gap: 10,
|
|
36
|
+
padding: '10px 12px',
|
|
37
|
+
cursor: 'pointer',
|
|
38
|
+
},
|
|
39
|
+
flag: {
|
|
40
|
+
fontSize: 20,
|
|
41
|
+
},
|
|
42
|
+
name: {
|
|
43
|
+
flex: 1,
|
|
44
|
+
fontSize: 14,
|
|
45
|
+
color: '#222',
|
|
46
|
+
},
|
|
47
|
+
dial: {
|
|
48
|
+
fontSize: 13,
|
|
49
|
+
color: '#888',
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
function CountryList({ onSelect, data, searchable = true, searchPlaceholder = 'Search country...', }) {
|
|
53
|
+
const [query, setQuery] = (0, react_1.useState)('');
|
|
54
|
+
const source = data !== null && data !== void 0 ? data : countries_json_1.default;
|
|
55
|
+
const filtered = (0, react_1.useMemo)(() => {
|
|
56
|
+
if (!query.trim())
|
|
57
|
+
return source;
|
|
58
|
+
const q = query.trim().toLowerCase();
|
|
59
|
+
return source.filter((c) => c.name.toLowerCase().includes(q) ||
|
|
60
|
+
c.dial_code.includes(q) ||
|
|
61
|
+
c.code.toLowerCase().includes(q));
|
|
62
|
+
}, [query, source]);
|
|
63
|
+
return ((0, jsx_runtime_1.jsxs)("div", { style: styles.container, children: [searchable && ((0, jsx_runtime_1.jsx)("input", { style: styles.search, placeholder: searchPlaceholder, value: query, onChange: (e) => setQuery(e.target.value) })), (0, jsx_runtime_1.jsx)("div", { style: styles.list, children: filtered.map((country) => ((0, jsx_runtime_1.jsxs)("div", { style: styles.row, onClick: () => onSelect(country), children: [(0, jsx_runtime_1.jsx)("span", { style: styles.flag, children: country.Icon }), (0, jsx_runtime_1.jsx)("span", { style: styles.name, children: country.name }), (0, jsx_runtime_1.jsx)("span", { style: styles.dial, children: country.dial_code })] }, country.code))) })] }));
|
|
64
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = CountryList;
|
|
7
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
|
+
const react_1 = require("react");
|
|
9
|
+
const react_native_1 = require("react-native");
|
|
10
|
+
const countries_json_1 = __importDefault(require("./data/countries.json"));
|
|
11
|
+
function CountryList({ onSelect, data, searchable = true, searchPlaceholder = 'Search country...', }) {
|
|
12
|
+
const [query, setQuery] = (0, react_1.useState)('');
|
|
13
|
+
const source = data !== null && data !== void 0 ? data : countries_json_1.default;
|
|
14
|
+
const filtered = (0, react_1.useMemo)(() => {
|
|
15
|
+
if (!query.trim())
|
|
16
|
+
return source;
|
|
17
|
+
const q = query.trim().toLowerCase();
|
|
18
|
+
return source.filter((c) => c.name.toLowerCase().includes(q) ||
|
|
19
|
+
c.dial_code.includes(q) ||
|
|
20
|
+
c.code.toLowerCase().includes(q));
|
|
21
|
+
}, [query, source]);
|
|
22
|
+
return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.container, children: [searchable && ((0, jsx_runtime_1.jsx)(react_native_1.TextInput, { style: styles.search, placeholder: searchPlaceholder, value: query, onChangeText: setQuery })), (0, jsx_runtime_1.jsx)(react_native_1.FlatList, { data: filtered, keyExtractor: (item) => item.code, renderItem: ({ item }) => ((0, jsx_runtime_1.jsxs)(react_native_1.TouchableOpacity, { style: styles.row, onPress: () => onSelect(item), children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.flag, children: item.Icon }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.name, children: item.name }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: styles.dial, children: item.dial_code })] })) })] }));
|
|
23
|
+
}
|
|
24
|
+
const styles = react_native_1.StyleSheet.create({
|
|
25
|
+
container: {
|
|
26
|
+
width: '100%',
|
|
27
|
+
maxWidth: 360,
|
|
28
|
+
borderWidth: 1,
|
|
29
|
+
borderColor: '#e0e0e0',
|
|
30
|
+
borderRadius: 8,
|
|
31
|
+
overflow: 'hidden',
|
|
32
|
+
},
|
|
33
|
+
search: {
|
|
34
|
+
paddingHorizontal: 12,
|
|
35
|
+
paddingVertical: 10,
|
|
36
|
+
borderBottomWidth: 1,
|
|
37
|
+
borderBottomColor: '#e0e0e0',
|
|
38
|
+
fontSize: 14,
|
|
39
|
+
},
|
|
40
|
+
row: {
|
|
41
|
+
flexDirection: 'row',
|
|
42
|
+
alignItems: 'center',
|
|
43
|
+
paddingHorizontal: 12,
|
|
44
|
+
paddingVertical: 10,
|
|
45
|
+
gap: 10,
|
|
46
|
+
},
|
|
47
|
+
flag: {
|
|
48
|
+
fontSize: 20,
|
|
49
|
+
marginRight: 10,
|
|
50
|
+
},
|
|
51
|
+
name: {
|
|
52
|
+
flex: 1,
|
|
53
|
+
fontSize: 14,
|
|
54
|
+
color: '#222',
|
|
55
|
+
},
|
|
56
|
+
dial: {
|
|
57
|
+
fontSize: 13,
|
|
58
|
+
color: '#888',
|
|
59
|
+
},
|
|
60
|
+
});
|