@mountainpass/addressr-react
Advanced tools
+13
-36
| { | ||
| "name": "@mountainpass/addressr-react", | ||
| "version": "0.2.0", | ||
| "version": "0.4.0", | ||
| "description": "React address autocomplete component for Australian address search via Addressr", | ||
@@ -16,5 +16,5 @@ "author": { | ||
| ".": { | ||
| "types": "./dist/index.d.ts", | ||
| "import": "./dist/index.mjs", | ||
| "require": "./dist/index.cjs", | ||
| "types": "./dist/index.d.ts" | ||
| "require": "./dist/index.cjs" | ||
| }, | ||
@@ -32,12 +32,2 @@ "./style.css": "./dist/style.css" | ||
| }, | ||
| "scripts": { | ||
| "dev": "vite", | ||
| "build": "tsc && vite build", | ||
| "test": "vitest run", | ||
| "test:watch": "vitest", | ||
| "lint": "eslint src/", | ||
| "pre-commit": "lint-staged", | ||
| "push:watch": "bash scripts/push-and-watch.sh", | ||
| "release:watch": "bash scripts/release-watch.sh" | ||
| }, | ||
| "peerDependencies": { | ||
@@ -48,8 +38,7 @@ "react": ">=18", | ||
| "dependencies": { | ||
| "@windyroad/fetch-link": "^3.0.5", | ||
| "downshift": "^9.0.0" | ||
| "@windyroad/link-header": "^1.0.1", | ||
| "downshift": "^9.0.0", | ||
| "@mountainpass/addressr-core": "0.4.0" | ||
| }, | ||
| "devDependencies": { | ||
| "@changesets/cli": "^2.29.7", | ||
| "@eslint/js": "^9.39.4", | ||
| "@testing-library/jest-dom": "^6.6.3", | ||
@@ -61,15 +50,6 @@ "@testing-library/react": "^16.3.0", | ||
| "@vitejs/plugin-react": "^4.5.2", | ||
| "eslint": "^9.39.4", | ||
| "eslint-config-prettier": "^10.1.8", | ||
| "eslint-plugin-prettier": "^5.5.5", | ||
| "eslint-plugin-react-hooks": "^5.2.0", | ||
| "globals": "^17.4.0", | ||
| "husky": "^9.1.7", | ||
| "jsdom": "^26.1.0", | ||
| "lint-staged": "^16.3.3", | ||
| "prettier": "^3.8.1", | ||
| "react": "^18.3.1", | ||
| "react-dom": "^18.3.1", | ||
| "typescript": "^5.8.3", | ||
| "typescript-eslint": "^8.58.0", | ||
| "vite": "^6.3.5", | ||
@@ -79,13 +59,5 @@ "vite-plugin-dts": "^4.5.4", | ||
| }, | ||
| "lint-staged": { | ||
| "*.{ts,tsx}": "eslint --fix", | ||
| "*.{json,css,md}": "prettier --write" | ||
| }, | ||
| "publishConfig": { | ||
| "access": "public" | ||
| }, | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "git+https://github.com/mountain-pass/addressr-react.git" | ||
| }, | ||
| "keywords": [ | ||
@@ -100,3 +72,8 @@ "react", | ||
| "hateoas" | ||
| ] | ||
| } | ||
| ], | ||
| "scripts": { | ||
| "build": "tsc --noEmit && vite build", | ||
| "test": "vitest run", | ||
| "lint": "eslint -c eslint.config.js src/" | ||
| } | ||
| } |
+57
-75
| # @mountainpass/addressr-react | ||
| React address autocomplete component for Australian address search powered by [Addressr](https://addressr.io). | ||
| React address autocomplete component for Australian address search, powered by [Addressr](https://addressr.io). | ||
| Search, validate, and retrieve detailed Australian address data from the Geocoded National Address File (G-NAF). | ||
| Part of the [addressr-ui](https://github.com/mountain-pass/addressr-ui) monorepo. | ||
| ## Quick Start | ||
| ## Install | ||
| ### 1. Get an API Key | ||
| Sign up at [RapidAPI](https://rapidapi.com/addressr-addressr-default/api/addressr) to get your API key. | ||
| ### 2. Install | ||
| ```bash | ||
@@ -19,4 +13,6 @@ npm install @mountainpass/addressr-react | ||
| ### 3. Use the Component | ||
| Peer dependencies: `react` >= 18, `react-dom` >= 18. | ||
| ## Drop-in component | ||
| ```tsx | ||
@@ -29,7 +25,7 @@ import { AddressAutocomplete } from '@mountainpass/addressr-react'; | ||
| <AddressAutocomplete | ||
| apiKey="your-rapidapi-key" | ||
| apiUrl="https://api.addressr.io/" | ||
| onSelect={(address) => { | ||
| console.log(address.sla); // "1 GEORGE ST, SYDNEY NSW 2000" | ||
| console.log(address.structured); // { street, locality, state, postcode, ... } | ||
| console.log(address.geocoding); // { latitude, longitude, ... } | ||
| console.log(address.sla); // "1 GEORGE ST, SYDNEY NSW 2000" | ||
| console.log(address.structured); // { street, locality, state, postcode, ... } | ||
| console.log(address.geocoding); // { latitude, longitude, ... } | ||
| }} | ||
@@ -41,4 +37,19 @@ /> | ||
| ### Or Use the Headless Hook | ||
| ### Props | ||
| | Prop | Type | Default | Description | | ||
| |------|------|---------|-------------| | ||
| | `apiKey` | `string` | -- | RapidAPI key. Omit for direct API access. | | ||
| | `onSelect` | `(address: AddressDetail) => void` | **required** | Called when an address is selected | | ||
| | `label` | `string` | `"Search Australian addresses"` | Accessible label text | | ||
| | `placeholder` | `string` | `"Start typing an address..."` | Input placeholder | | ||
| | `className` | `string` | -- | Additional CSS class for the wrapper | | ||
| | `debounceMs` | `number` | `300` | Debounce delay in milliseconds | | ||
| | `apiUrl` | `string` | `"https://addressr.p.rapidapi.com/"` | API root URL | | ||
| | `apiHost` | `string` | `"addressr.p.rapidapi.com"` | RapidAPI host header | | ||
| ## Headless hook | ||
| Build your own UI while keeping the search logic, debounce, pagination, and abort handling: | ||
| ```tsx | ||
@@ -49,29 +60,18 @@ import { useAddressSearch } from '@mountainpass/addressr-react'; | ||
| const { | ||
| query, | ||
| setQuery, | ||
| results, | ||
| isLoading, | ||
| selectedAddress, | ||
| selectAddress, | ||
| clear, | ||
| } = useAddressSearch({ apiKey: 'your-rapidapi-key' }); | ||
| query, setQuery, | ||
| results, isLoading, | ||
| hasMore, loadMore, isLoadingMore, | ||
| selectedAddress, selectAddress, | ||
| error, clear, | ||
| } = useAddressSearch({ apiUrl: 'https://api.addressr.io/' }); | ||
| return ( | ||
| <div> | ||
| <input | ||
| value={query} | ||
| onChange={(e) => setQuery(e.target.value)} | ||
| placeholder="Search addresses..." | ||
| /> | ||
| {isLoading && <p>Searching...</p>} | ||
| <input value={query} onChange={(e) => setQuery(e.target.value)} /> | ||
| <ul> | ||
| {results.map((result) => ( | ||
| <li key={result.pid} onClick={() => selectAddress(result.pid)}> | ||
| {result.sla} | ||
| </li> | ||
| {results.map((r) => ( | ||
| <li key={r.pid} onClick={() => selectAddress(r.pid)}>{r.sla}</li> | ||
| ))} | ||
| {hasMore && <li onClick={loadMore}>Load more...</li>} | ||
| </ul> | ||
| {selectedAddress && ( | ||
| <pre>{JSON.stringify(selectedAddress, null, 2)}</pre> | ||
| )} | ||
| </div> | ||
@@ -82,50 +82,32 @@ ); | ||
| ## API | ||
| ### Return values | ||
| ### `<AddressAutocomplete />` | ||
| | Property | Type | Description | | ||
| |----------|------|-------------| | ||
| | `query` | `string` | Current input value | | ||
| | `setQuery` | `(q: string) => void` | Update query (triggers debounced search) | | ||
| | `results` | `AddressSearchResult[]` | Search results (accumulated across pages) | | ||
| | `isLoading` | `boolean` | Initial search in progress | | ||
| | `isLoadingMore` | `boolean` | Pagination fetch in progress | | ||
| | `hasMore` | `boolean` | More pages available | | ||
| | `loadMore` | `() => Promise<void>` | Load next page of results | | ||
| | `error` | `Error \| null` | Latest error | | ||
| | `selectedAddress` | `AddressDetail \| null` | Selected address detail | | ||
| | `selectAddress` | `(pid: string) => Promise<void>` | Fetch full address detail | | ||
| | `clear` | `() => void` | Reset all state | | ||
| | Prop | Type | Default | Description | | ||
| |------|------|---------|-------------| | ||
| | `apiKey` | `string` | required | RapidAPI key | | ||
| | `onSelect` | `(address: AddressDetail) => void` | required | Called when an address is selected | | ||
| | `label` | `string` | `"Search Australian addresses"` | Accessible label | | ||
| | `placeholder` | `string` | `"Start typing an address..."` | Input placeholder | | ||
| | `className` | `string` | — | Additional CSS class for the wrapper | | ||
| | `debounceMs` | `number` | `300` | Debounce delay in milliseconds | | ||
| | `apiUrl` | `string` | `"https://addressr.p.rapidapi.com/"` | API root URL | | ||
| ## Accessibility | ||
| ### `useAddressSearch(options)` | ||
| Built with [downshift](https://www.downshift-js.com/) for WAI-ARIA combobox pattern compliance: | ||
| Returns `{ query, setQuery, results, isLoading, error, selectedAddress, selectAddress, clear }`. | ||
| | Option | Type | Default | Description | | ||
| |--------|------|---------|-------------| | ||
| | `apiKey` | `string` | required | RapidAPI key | | ||
| | `apiUrl` | `string` | `"https://addressr.p.rapidapi.com/"` | API root URL | | ||
| | `debounceMs` | `number` | `300` | Debounce delay | | ||
| | `minQueryLength` | `number` | `3` | Minimum characters before searching | | ||
| ### `createAddressrClient(options)` | ||
| Low-level API client for direct use. Returns `{ searchAddresses, getAddressDetail }`. | ||
| ## Architecture | ||
| - **HATEOAS** — the component discovers API endpoints via RFC 8288 Link headers, not hardcoded paths | ||
| - **downshift** — WAI-ARIA APG combobox pattern with full keyboard navigation and screen reader support | ||
| - **CSS Modules** — scoped styles, override via `className` prop | ||
| - **Safe highlights** — search match highlighting rendered via `<mark>` elements, never `dangerouslySetInnerHTML` | ||
| ## Accessibility | ||
| - WCAG AA compliant | ||
| - Full keyboard navigation (arrow keys, Enter, Escape) | ||
| - Full keyboard navigation (Arrow keys, Enter, Escape) | ||
| - Screen reader announcements for results count and loading state | ||
| - Visible focus indicators (3:1 contrast ratio) | ||
| - Visible focus indicators (3:1 contrast) | ||
| - Touch targets >= 44px | ||
| - Accessible label always present | ||
| - Infinite scroll with loading indicator | ||
| ## Data Source | ||
| ## Re-exports | ||
| Address data from the [Geocoded National Address File (G-NAF)](https://data.gov.au/dataset/ds-dga-19432f89-dc3a-4ef3-b943-5326ef1dbecc), Australia's authoritative address database. | ||
| This package re-exports everything from [`@mountainpass/addressr-core`](../core) for convenience -- `createAddressrClient`, `parseHighlight`, and all types. | ||
@@ -132,0 +114,0 @@ ## License |
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
13
-45.83%11518
-7.31%5
25%112
-13.85%1
Infinity%+ Added
- Removed