{"_id":"@acuminx/react-native-country-picker-universal","_rev":"2-26f9430c9ece9e61c72895675bf5fafb","name":"@acuminx/react-native-country-picker-universal","dist-tags":{"latest":"1.0.9"},"versions":{"1.0.8":{"name":"@acuminx/react-native-country-picker-universal","version":"1.0.8","keywords":["expo","react-native","react","country","selector"],"author":{"name":"Paul"},"license":"ISC","_id":"@acuminx/react-native-country-picker-universal@1.0.8","maintainers":[{"name":"paul24","email":"to.paul24@gmail.com"}],"dist":{"shasum":"2638acc58e92b6d3f17f40e523a106d82b090f51","tarball":"https://registry.npmjs.org/@acuminx/react-native-country-picker-universal/-/react-native-country-picker-universal-1.0.8.tgz","fileCount":24,"integrity":"sha512-Cqe9CT8DBxz3sBcXNKRgv6ySlk3YdAUDT4egPlR50JulQMbcth0jjSIKWkGKukN49umISfhCW1Uwe8Th2JJb8w==","signatures":[{"sig":"MEUCIBgUf72jzjqhWmq9eZKFTJxz7p9eelixx2Z9bMZBkehZAiEAgXMe+9b1q2O/2dIE+qKL7mNaguIo6ujOBd8A3Bhgnpk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":483106},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","default":"./dist/index.js","require":"./dist/index.js","react-native":"./src/index.ts"},"./package.json":"./package.json"},"gitHead":"b822ab185ea62eb6676c3fabd2f20473c466f75f","scripts":{"dev":"vite --port=3000 --host=0.0.0.0","lint":"tsc --noEmit","test":"jest","build":"vite build","clean":"rm -rf dist server.js","preview":"vite preview","test:coverage":"jest --coverage"},"_npmUser":{"name":"paul24","email":"to.paul24@gmail.com"},"repository":{"url":"react-native-country-picker-universal","type":"git"},"_npmVersion":"11.17.0","description":"Cross-platform universal Country Dropdown Picker for React 19.2.x, React Native 0.86.x, and Expo SDK 57.0.x","directories":{},"_nodeVersion":"24.19.0","dependencies":{"vite":"^6.2.3","react":"^19.2.0","dotenv":"^17.2.3","motion":"^12.23.24","express":"^4.21.2","react-dom":"^19.0.1","lucide-react":"^0.546.0","@google/genai":"^2.4.0","@tailwindcss/vite":"^4.1.14","@vitejs/plugin-react":"^5.0.4"},"react-native":"src/index.ts","publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","jest":"^30.5.0","vite":"^6.2.3","esbuild":"^0.25.0","ts-jest":"^29.4.12","typescript":"~5.8.2","@types/jest":"^30.0.0","@types/node":"^22.14.0","tailwindcss":"^4.1.14","@types/react":"^19.0.0","autoprefixer":"^10.4.21","@types/express":"^4.17.21","@types/react-dom":"^19.0.0","@types/react-native":"^0.73.0","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.3","jest-environment-jsdom":"^30.5.0","@testing-library/jest-dom":"^7.0.1"},"peerDependencies":{"react":"^19.2.0","react-native":"^0.86.0"},"peerDependenciesMeta":{"react-native":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/react-native-country-picker-universal_1.0.8_1787978058750_0.889935757108266","host":"s3://npm-registry-packages-npm-production"}},"1.0.9":{"name":"@acuminx/react-native-country-picker-universal","version":"1.0.9","description":"Cross-platform universal Country Dropdown Picker for React 19.2.x, React Native 0.86.x, and Expo SDK 57.0.x","main":"dist/index.js","module":"dist/index.mjs","types":"dist/index.d.ts","react-native":"src/index.ts","exports":{".":{"types":"./dist/index.d.ts","react-native":"./src/index.ts","import":"./dist/index.mjs","require":"./dist/index.js","default":"./dist/index.js"},"./package.json":"./package.json"},"scripts":{"dev":"vite --port=3000 --host=0.0.0.0","build":"vite build","test":"jest","test:coverage":"jest --coverage","preview":"vite preview","clean":"rm -rf dist server.js","lint":"tsc --noEmit"},"peerDependencies":{"react":"^19.2.0","react-native":"^0.86.0"},"peerDependenciesMeta":{"react-native":{"optional":true}},"dependencies":{"@google/genai":"^2.4.0","@tailwindcss/vite":"^4.1.14","@vitejs/plugin-react":"^5.0.4","dotenv":"^17.2.3","express":"^4.21.2","lucide-react":"^0.546.0","motion":"^12.23.24","react":"^19.2.0","react-dom":"^19.0.1","vite":"^6.2.3"},"devDependencies":{"@testing-library/dom":"^10.4.1","@testing-library/jest-dom":"^7.0.1","@testing-library/react":"^16.3.3","@types/express":"^4.17.21","@types/jest":"^30.0.0","@types/node":"^22.14.0","@types/react":"^19.0.0","@types/react-dom":"^19.0.0","@types/react-native":"^0.73.0","autoprefixer":"^10.4.21","esbuild":"^0.25.0","jest":"^30.5.0","jest-environment-jsdom":"^30.5.0","tailwindcss":"^4.1.14","ts-jest":"^29.4.12","tsx":"^4.21.0","typescript":"~5.8.2","vite":"^6.2.3"},"repository":{"type":"git","url":"git+https://github.com/PAUL24/react-native-country-picker-universal.git"},"keywords":["expo","react-native","react","country","selector"],"author":{"name":"Paul"},"license":"ISC","publishConfig":{"registry":"https://registry.npmjs.org/","access":"public"},"gitHead":"770fdbf2a14cc439feb3e20ae7e4164ae94ec16a","_id":"@acuminx/react-native-country-picker-universal@1.0.9","bugs":{"url":"https://github.com/PAUL24/react-native-country-picker-universal/issues"},"homepage":"https://github.com/PAUL24/react-native-country-picker-universal#readme","_nodeVersion":"24.19.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-3wbxiD5ZgUom4Rjln0TKPhuVLb4Pv09Pgxo7ukkM56fwiyJi36Oxj27zvDpIEf1Zbyzj3fW/s0cTkqIr1IoZmQ==","shasum":"b8f6a6c6fb26e550f008173443620cde70eadf1f","tarball":"https://registry.npmjs.org/@acuminx/react-native-country-picker-universal/-/react-native-country-picker-universal-1.0.9.tgz","fileCount":24,"unpackedSize":483140,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@acuminx%2freact-native-country-picker-universal@1.0.9","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDtDswpjya3Tjz4hEYlGGdBLNU8P51IFqTHXlOQnRILBAiApZ+VVJPum2sMdkxIid6CHER1eUeotx60z/PVyeYR3zg=="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:80e6d48d-44e5-4142-a854-763d18342150"}},"directories":{},"maintainers":[{"name":"paul24","email":"to.paul24@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/react-native-country-picker-universal_1.0.9_1787979396858_0.7811545760271257"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-29T04:34:18.617Z","modified":"2026-08-29T04:56:37.368Z","1.0.8":"2026-08-29T04:34:18.909Z","1.0.9":"2026-08-29T04:56:37.020Z"},"author":{"name":"Paul"},"license":"ISC","keywords":["expo","react-native","react","country","selector"],"repository":{"type":"git","url":"git+https://github.com/PAUL24/react-native-country-picker-universal.git"},"description":"Cross-platform universal Country Dropdown Picker for React 19.2.x, React Native 0.86.x, and Expo SDK 57.0.x","maintainers":[{"name":"paul24","email":"to.paul24@gmail.com"}],"readme":"# react-native-country-picker-universal 🌐\n\nA sleek, lightweight, cross-platform Country Dropdown Picker built for **universal web and mobile applications**. Engineered specifically with zero native binary build dependencies, full **React 19.2.x**, **React Native 0.86.x**, and **Expo SDK 57.0.x** compatibility out-of-the-box.\n\n---\n\n## ⚡ Key Highlights\n\n- **Universal Architecture**: Dual-resolution compiling with platform filename conventions (`CountryPicker.web.tsx` for web, `CountryPicker.tsx` for mobile).\n- **Expo SDK 57 & Expo Go Ready**: Built entirely from core React Native primitives (`<Modal>`, `<FlatList>`, `<TextInput>`, `<Pressable>`). Works immediately in Expo Go without native custom builds or prebuild steps.\n- **Modern React 19.2.x Support**: Native ref forwarding support (`ref.open()`, `ref.close()`, `ref.getSelected()`), updated hook conventions, and strict typing.\n- **Zero Image Overhead**: Uses native Unicode Emoji Flags (e.g., 🇺🇸, 🇬🇧, 🇨🇦, 🇦🇺, 🇳🇿, 🇩🇪, 🇯🇵) instead of bundling heavy raster PNGs or SVG font packages.\n- **Interactive Search & Filter**: Real-time filtering by country name, ISO 3166-1 alpha-2 code, or international dialing code (e.g. `+1`, `+44`).\n- **Fully Customizable & Accessible**: Customizable layout styling tokens (`customStyles`), custom trigger and item render callbacks, WAI-ARIA / screen-reader accessibility semantics.\n\n---\n\n## 📦 Installation\n\n```bash\n# Using Expo CLI\nnpx expo install react-native-country-picker-universal\n\n# Using npm\nnpm install react-native-country-picker-universal\n\n# Using yarn\nyarn add react-native-country-picker-universal\n\n# Using pnpm\npnpm add react-native-country-picker-universal\n```\n\n### Peer Dependencies\nThis package requires the following peer dependencies in your workspace:\n\n```json\n{\n  \"peerDependencies\": {\n    \"react\": \"^19.2.0\",\n    \"react-native\": \"^0.86.0\"\n  }\n}\n```\n\n*(Note: `react-native` is marked optional in peerDependenciesMeta for pure web React 19 applications).*\n\n---\n\n## 🚀 Quick Start\n\n### 1. Basic Universal Usage\n\nBecause of dual-resolution exports, you can import and use `CountryPicker` identically across both Web and Mobile React Native code:\n\n```tsx\nimport React, { useState } from 'react';\nimport { View, Text, StyleSheet } from 'react-native';\nimport { CountryPicker, type Country } from 'react-native-country-picker-universal';\n\nexport default function App() {\n  const [selectedCountry, setSelectedCountry] = useState<Country | null>(null);\n\n  return (\n    <View style={styles.container}>\n      <Text style={styles.label}>Select Nationality:</Text>\n      \n      <CountryPicker\n        value={selectedCountry}\n        onChange={(country) => {\n          console.log('Selected:', country);\n          setSelectedCountry(country);\n        }}\n        placeholder=\"Choose your country\"\n        showDialCode={true}\n        showFlag={true}\n      />\n\n      {selectedCountry && (\n        <Text style={styles.result}>\n          Selected: {selectedCountry.flag} {selectedCountry.name} ({selectedCountry.dialCode})\n        </Text>\n      )}\n    </View>\n  );\n}\n\nconst styles = StyleSheet.create({\n  container: {\n    padding: 24,\n    backgroundColor: '#fff',\n    flex: 1,\n    justifyContent: 'center',\n  },\n  label: {\n    fontSize: 14,\n    fontWeight: '600',\n    color: '#374151',\n    marginBottom: 8,\n  },\n  result: {\n    marginTop: 16,\n    fontSize: 14,\n    color: '#111827',\n  },\n});\n```\n\n---\n\n## 🛠️ Advanced Usage & React 19 Ref API\n\nYou can programmatically control the dropdown or modal using imperative `ref` methods:\n\n```tsx\nimport React, { useRef } from 'react';\nimport { CountryPicker, type CountryPickerRef } from 'react-native-country-picker-universal';\n\nexport function ControlledForm() {\n  const pickerRef = useRef<CountryPickerRef>(null);\n\n  return (\n    <div>\n      <CountryPicker ref={pickerRef} value=\"US\" />\n\n      <div style={{ marginTop: 12, display: 'flex', gap: 8 }}>\n        <button onClick={() => pickerRef.current?.open()}>Open Picker</button>\n        <button onClick={() => pickerRef.current?.close()}>Close Picker</button>\n        <button onClick={() => pickerRef.current?.toggle()}>Toggle</button>\n        <button onClick={() => alert(JSON.stringify(pickerRef.current?.getSelected()))}>\n          Get Selection\n        </button>\n      </div>\n    </div>\n  );\n}\n```\n\n---\n\n## 🎨 Custom Trigger & Render Props\n\nYou can replace the default trigger bar or list item rows with custom design elements:\n\n```tsx\n<CountryPicker\n  value=\"NZ\"\n  renderTrigger={(selectedCountry, isOpen, openPicker) => (\n    <button onClick={openPicker} className=\"custom-trigger-button\">\n      {selectedCountry ? `${selectedCountry.flag} ${selectedCountry.name}` : 'Select...'}\n    </button>\n  )}\n  renderItem={(country, isSelected, onSelect) => (\n    <div\n      onClick={onSelect}\n      className={`custom-item-row \\${isSelected ? 'active' : ''}`}\n    >\n      <span>{country.flag}</span>\n      <span>{country.name}</span>\n      <code>{country.dialCode}</code>\n    </div>\n  )}\n/>\n```\n\n---\n\n## 📖 API Reference\n\n### `<CountryPicker />` Props\n\n| Prop | Type | Default | Description |\n| :--- | :--- | :--- | :--- |\n| `value` | `Country \\| string \\| null` | `null` | Currently selected country object or ISO 2-letter code (e.g., `'US'`, `'NZ'`). |\n| `onChange` | `(country: Country) => void` | `undefined` | Callback fired when a country is selected. |\n| `countries` | `Country[]` | Standard Dataset | Custom dataset array. If omitted, the default 20+ countries dataset is used. |\n| `placeholder` | `string` | `\"Select a country\"` | Placeholder label when no country is selected. |\n| `searchPlaceholder` | `string` | `\"Search country or dialing code...\"` | Placeholder text inside the search filter `<TextInput>`. |\n| `modalTitle` | `string` | `\"Select Country\"` | Title displayed in the Mobile modal header. |\n| `disabled` | `boolean` | `false` | Whether the picker is disabled. |\n| `showDialCode` | `boolean` | `true` | Whether to display calling codes (`+1`, `+44`). |\n| `showFlag` | `boolean` | `true` | Whether to display native Unicode flag emojis. |\n| `autoFocusSearch` | `boolean` | `true` | Whether to automatically focus search input when opened. |\n| `closeOnSelect` | `boolean` | `true` | Automatically dismiss dropdown/modal upon item selection. |\n| `customStyles` | `CountryPickerCustomStyles` | `{}` | Custom styling overrides for container, trigger, modal, list rows, etc. |\n| `renderTrigger` | `(country, isOpen, open) => ReactNode` | `undefined` | Custom trigger component renderer. |\n| `renderItem` | `(country, isSelected, onSelect) => ReactNode` | `undefined` | Custom list item row renderer. |\n\n### `Country` Type Definition\n\n```typescript\nexport interface Country {\n  code: string;     // ISO 3166-1 alpha-2 two-letter code (e.g. \"US\", \"GB\", \"NZ\")\n  name: string;     // English Country Name\n  flag: string;     // Native Unicode Emoji Flag (e.g. \"🇺🇸\", \"🇬🇧\", \"🇳🇿\")\n  dialCode: string; // Calling Code with '+' prefix (e.g. \"+1\", \"+44\", \"+64\")\n}\n```\n\n### Dataset & Helper Functions\n\nThe package also exports standalone utilities and the country dataset for manual filtering:\n\n```typescript\nimport { countries, getCountryByCode, searchCountries } from 'react-native-country-picker-universal';\n\n// Lookup country by 2-letter ISO code\nconst uk = getCountryByCode('GB');\n\n// Filter countries with query string\nconst matches = searchCountries('united');\n```\n\n---\n\n## 🏗️ Project Architecture & Dual Resolution\n\n```\n├── src/\n│   ├── data/\n│   │   └── countries.ts         # Strongly typed dataset with Unicode emoji flags & lookup helpers\n│   ├── types.ts                 # Shared universal TypeScript interfaces\n│   ├── CountryPicker.web.tsx    # Web implementation (search, keyboard navigation, popover)\n│   ├── CountryPicker.tsx        # Mobile React Native implementation (<Modal>, <FlatList>, <Pressable>)\n│   └── index.ts                 # Universal barrel entry\n├── package.json                 # Dual-resolution exports (\"react-native\": \"src/index.ts\")\n├── tsconfig.json                # Modern React 19 compiler options\n└── README.md                    # Detailed documentation & guides\n```\n\n### Metro & Expo 57 Resolution\nIn `package.json`:\n- `\"react-native\": \"src/index.ts\"` allows the Metro bundler in Expo 57 to resolve and compile TypeScript directly.\n- `\"main\": \"dist/index.js\"` and `\"exports\"` allow standard bundlers (Vite, Webpack, Next.js, Rollup) to consume pre-bundled builds.\n\n---\n\n## 🧪 Jest Automated Test Suite\n\nThe package includes a comprehensive, 100% automated test suite using **Jest 29.7**, **ts-jest**, **@testing-library/react**, and **jest-environment-jsdom**.\n\n### Test Suite Structure\n\n```\n├── src/\n│   ├── data/\n│   │   └── __tests__/\n│   │       └── countries.test.ts          # Dataset integrity, ISO-2 lookup, dialing code search\n│   ├── __tests__/\n│   │   ├── CountryPicker.web.test.tsx     # Web component rendering, a11y, keyboard nav, React 19 Ref API\n│   │   ├── CountryPicker.native.test.tsx  # React Native / Expo <Modal>, <FlatList>, <Pressable> primitives\n│   │   └── universal-export.test.ts       # Root index barrel exports & module integrity\n│   ├── __mocks__/\n│   │   ├── react-native.js               # React Native core primitive mock layer for JSDOM\n│   │   └── styleMock.js                  # CSS stylesheet mock\n│   └── setupTests.ts                     # Jest DOM assertions setup (@testing-library/jest-dom)\n└── jest.config.cjs                       # Jest & ts-jest test runner configuration\n```\n\n### Running Tests\n\n```bash\n# Run all test suites\nnpm test\n\n# Run tests with code coverage report\nnpm run test:coverage\n\n# Run tests in interactive watch mode\nnpx jest --watch\n```\n\n### Test Coverage Highlights\n\n- **Country Dataset (`src/data/countries.ts`)**: 100% validation of ISO 3166-1 alpha-2 codes, uniqueness, dial codes, Unicode flag emojis, case-insensitive code lookups, and substring search logic.\n- **Web Component (`src/CountryPicker.web.tsx`)**: Complete coverage of listbox triggers, search filtering, click-outside handling, Escape key dismissal, and imperative Ref methods (`open()`, `close()`, `toggle()`, `getSelected()`).\n- **React Native Component (`src/CountryPicker.tsx`)**: Verification of `<Modal>` slide-up presentation, `<FlatList>` item rendering, search query state updates, and selection dismissal.\n- **Universal Exports (`src/index.ts`)**: Asserts that all public types, components, and dataset utilities are cleanly exported.\n\n---\n\n## 📄 License\n\nMIT © 2026\n","readmeFilename":"README.md","homepage":"https://github.com/PAUL24/react-native-country-picker-universal#readme","bugs":{"url":"https://github.com/PAUL24/react-native-country-picker-universal/issues"}}