@mountainpass/addressr-react 0.2.0 → 0.4.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 +58 -76
- package/package.json +13 -36
package/README.md
CHANGED
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
# @mountainpass/addressr-react
|
|
2
2
|
|
|
3
|
-
React address autocomplete component for Australian address search powered by [Addressr](https://addressr.io).
|
|
3
|
+
React address autocomplete component for Australian address search, powered by [Addressr](https://addressr.io).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Part of the [addressr-ui](https://github.com/mountain-pass/addressr-ui) monorepo.
|
|
6
6
|
|
|
7
|
-
##
|
|
8
|
-
|
|
9
|
-
### 1. Get an API Key
|
|
10
|
-
|
|
11
|
-
Sign up at [RapidAPI](https://rapidapi.com/addressr-addressr-default/api/addressr) to get your API key.
|
|
12
|
-
|
|
13
|
-
### 2. Install
|
|
7
|
+
## Install
|
|
14
8
|
|
|
15
9
|
```bash
|
|
16
10
|
npm install @mountainpass/addressr-react
|
|
17
11
|
```
|
|
18
12
|
|
|
19
|
-
|
|
13
|
+
Peer dependencies: `react` >= 18, `react-dom` >= 18.
|
|
14
|
+
|
|
15
|
+
## Drop-in component
|
|
20
16
|
|
|
21
17
|
```tsx
|
|
22
18
|
import { AddressAutocomplete } from '@mountainpass/addressr-react';
|
|
@@ -25,104 +21,90 @@ import '@mountainpass/addressr-react/style.css';
|
|
|
25
21
|
function MyForm() {
|
|
26
22
|
return (
|
|
27
23
|
<AddressAutocomplete
|
|
28
|
-
|
|
24
|
+
apiUrl="https://api.addressr.io/"
|
|
29
25
|
onSelect={(address) => {
|
|
30
|
-
console.log(address.sla);
|
|
31
|
-
console.log(address.structured);
|
|
32
|
-
console.log(address.geocoding);
|
|
26
|
+
console.log(address.sla); // "1 GEORGE ST, SYDNEY NSW 2000"
|
|
27
|
+
console.log(address.structured); // { street, locality, state, postcode, ... }
|
|
28
|
+
console.log(address.geocoding); // { latitude, longitude, ... }
|
|
33
29
|
}}
|
|
34
30
|
/>
|
|
35
31
|
);
|
|
36
32
|
}
|
|
37
33
|
```
|
|
38
34
|
|
|
39
|
-
###
|
|
35
|
+
### Props
|
|
36
|
+
|
|
37
|
+
| Prop | Type | Default | Description |
|
|
38
|
+
|------|------|---------|-------------|
|
|
39
|
+
| `apiKey` | `string` | -- | RapidAPI key. Omit for direct API access. |
|
|
40
|
+
| `onSelect` | `(address: AddressDetail) => void` | **required** | Called when an address is selected |
|
|
41
|
+
| `label` | `string` | `"Search Australian addresses"` | Accessible label text |
|
|
42
|
+
| `placeholder` | `string` | `"Start typing an address..."` | Input placeholder |
|
|
43
|
+
| `className` | `string` | -- | Additional CSS class for the wrapper |
|
|
44
|
+
| `debounceMs` | `number` | `300` | Debounce delay in milliseconds |
|
|
45
|
+
| `apiUrl` | `string` | `"https://addressr.p.rapidapi.com/"` | API root URL |
|
|
46
|
+
| `apiHost` | `string` | `"addressr.p.rapidapi.com"` | RapidAPI host header |
|
|
47
|
+
|
|
48
|
+
## Headless hook
|
|
49
|
+
|
|
50
|
+
Build your own UI while keeping the search logic, debounce, pagination, and abort handling:
|
|
40
51
|
|
|
41
52
|
```tsx
|
|
42
53
|
import { useAddressSearch } from '@mountainpass/addressr-react';
|
|
43
54
|
|
|
44
55
|
function MyCustomAutocomplete() {
|
|
45
56
|
const {
|
|
46
|
-
query,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
clear,
|
|
53
|
-
} = useAddressSearch({ apiKey: 'your-rapidapi-key' });
|
|
57
|
+
query, setQuery,
|
|
58
|
+
results, isLoading,
|
|
59
|
+
hasMore, loadMore, isLoadingMore,
|
|
60
|
+
selectedAddress, selectAddress,
|
|
61
|
+
error, clear,
|
|
62
|
+
} = useAddressSearch({ apiUrl: 'https://api.addressr.io/' });
|
|
54
63
|
|
|
55
64
|
return (
|
|
56
65
|
<div>
|
|
57
|
-
<input
|
|
58
|
-
value={query}
|
|
59
|
-
onChange={(e) => setQuery(e.target.value)}
|
|
60
|
-
placeholder="Search addresses..."
|
|
61
|
-
/>
|
|
62
|
-
{isLoading && <p>Searching...</p>}
|
|
66
|
+
<input value={query} onChange={(e) => setQuery(e.target.value)} />
|
|
63
67
|
<ul>
|
|
64
|
-
{results.map((
|
|
65
|
-
<li key={
|
|
66
|
-
{result.sla}
|
|
67
|
-
</li>
|
|
68
|
+
{results.map((r) => (
|
|
69
|
+
<li key={r.pid} onClick={() => selectAddress(r.pid)}>{r.sla}</li>
|
|
68
70
|
))}
|
|
71
|
+
{hasMore && <li onClick={loadMore}>Load more...</li>}
|
|
69
72
|
</ul>
|
|
70
|
-
{selectedAddress && (
|
|
71
|
-
<pre>{JSON.stringify(selectedAddress, null, 2)}</pre>
|
|
72
|
-
)}
|
|
73
73
|
</div>
|
|
74
74
|
);
|
|
75
75
|
}
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
|
83
|
-
|
|
84
|
-
| `
|
|
85
|
-
| `
|
|
86
|
-
| `
|
|
87
|
-
| `
|
|
88
|
-
| `
|
|
89
|
-
| `
|
|
90
|
-
| `
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
Returns `{ query, setQuery, results, isLoading, error, selectedAddress, selectAddress, clear }`.
|
|
95
|
-
|
|
96
|
-
| Option | Type | Default | Description |
|
|
97
|
-
|--------|------|---------|-------------|
|
|
98
|
-
| `apiKey` | `string` | required | RapidAPI key |
|
|
99
|
-
| `apiUrl` | `string` | `"https://addressr.p.rapidapi.com/"` | API root URL |
|
|
100
|
-
| `debounceMs` | `number` | `300` | Debounce delay |
|
|
101
|
-
| `minQueryLength` | `number` | `3` | Minimum characters before searching |
|
|
102
|
-
|
|
103
|
-
### `createAddressrClient(options)`
|
|
104
|
-
|
|
105
|
-
Low-level API client for direct use. Returns `{ searchAddresses, getAddressDetail }`.
|
|
106
|
-
|
|
107
|
-
## Architecture
|
|
108
|
-
|
|
109
|
-
- **HATEOAS** — the component discovers API endpoints via RFC 8288 Link headers, not hardcoded paths
|
|
110
|
-
- **downshift** — WAI-ARIA APG combobox pattern with full keyboard navigation and screen reader support
|
|
111
|
-
- **CSS Modules** — scoped styles, override via `className` prop
|
|
112
|
-
- **Safe highlights** — search match highlighting rendered via `<mark>` elements, never `dangerouslySetInnerHTML`
|
|
78
|
+
### Return values
|
|
79
|
+
|
|
80
|
+
| Property | Type | Description |
|
|
81
|
+
|----------|------|-------------|
|
|
82
|
+
| `query` | `string` | Current input value |
|
|
83
|
+
| `setQuery` | `(q: string) => void` | Update query (triggers debounced search) |
|
|
84
|
+
| `results` | `AddressSearchResult[]` | Search results (accumulated across pages) |
|
|
85
|
+
| `isLoading` | `boolean` | Initial search in progress |
|
|
86
|
+
| `isLoadingMore` | `boolean` | Pagination fetch in progress |
|
|
87
|
+
| `hasMore` | `boolean` | More pages available |
|
|
88
|
+
| `loadMore` | `() => Promise<void>` | Load next page of results |
|
|
89
|
+
| `error` | `Error \| null` | Latest error |
|
|
90
|
+
| `selectedAddress` | `AddressDetail \| null` | Selected address detail |
|
|
91
|
+
| `selectAddress` | `(pid: string) => Promise<void>` | Fetch full address detail |
|
|
92
|
+
| `clear` | `() => void` | Reset all state |
|
|
113
93
|
|
|
114
94
|
## Accessibility
|
|
115
95
|
|
|
116
|
-
-
|
|
117
|
-
|
|
96
|
+
Built with [downshift](https://www.downshift-js.com/) for WAI-ARIA combobox pattern compliance:
|
|
97
|
+
|
|
98
|
+
- Full keyboard navigation (Arrow keys, Enter, Escape)
|
|
118
99
|
- Screen reader announcements for results count and loading state
|
|
119
|
-
- Visible focus indicators (3:1 contrast
|
|
100
|
+
- Visible focus indicators (3:1 contrast)
|
|
120
101
|
- Touch targets >= 44px
|
|
121
102
|
- Accessible label always present
|
|
103
|
+
- Infinite scroll with loading indicator
|
|
122
104
|
|
|
123
|
-
##
|
|
105
|
+
## Re-exports
|
|
124
106
|
|
|
125
|
-
|
|
107
|
+
This package re-exports everything from [`@mountainpass/addressr-core`](../core) for convenience -- `createAddressrClient`, `parseHighlight`, and all types.
|
|
126
108
|
|
|
127
109
|
## License
|
|
128
110
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mountainpass/addressr-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "React address autocomplete component for Australian address search via Addressr",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Mountain Pass",
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
"types": "./dist/index.d.ts",
|
|
14
14
|
"exports": {
|
|
15
15
|
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
16
17
|
"import": "./dist/index.mjs",
|
|
17
|
-
"require": "./dist/index.cjs"
|
|
18
|
-
"types": "./dist/index.d.ts"
|
|
18
|
+
"require": "./dist/index.cjs"
|
|
19
19
|
},
|
|
20
20
|
"./style.css": "./dist/style.css"
|
|
21
21
|
},
|
|
@@ -28,61 +28,33 @@
|
|
|
28
28
|
"engines": {
|
|
29
29
|
"node": ">=18"
|
|
30
30
|
},
|
|
31
|
-
"scripts": {
|
|
32
|
-
"dev": "vite",
|
|
33
|
-
"build": "tsc && vite build",
|
|
34
|
-
"test": "vitest run",
|
|
35
|
-
"test:watch": "vitest",
|
|
36
|
-
"lint": "eslint src/",
|
|
37
|
-
"pre-commit": "lint-staged",
|
|
38
|
-
"push:watch": "bash scripts/push-and-watch.sh",
|
|
39
|
-
"release:watch": "bash scripts/release-watch.sh"
|
|
40
|
-
},
|
|
41
31
|
"peerDependencies": {
|
|
42
32
|
"react": ">=18",
|
|
43
33
|
"react-dom": ">=18"
|
|
44
34
|
},
|
|
45
35
|
"dependencies": {
|
|
46
|
-
"@windyroad/
|
|
47
|
-
"downshift": "^9.0.0"
|
|
36
|
+
"@windyroad/link-header": "^1.0.1",
|
|
37
|
+
"downshift": "^9.0.0",
|
|
38
|
+
"@mountainpass/addressr-core": "0.4.0"
|
|
48
39
|
},
|
|
49
40
|
"devDependencies": {
|
|
50
|
-
"@changesets/cli": "^2.29.7",
|
|
51
|
-
"@eslint/js": "^9.39.4",
|
|
52
41
|
"@testing-library/jest-dom": "^6.6.3",
|
|
53
42
|
"@testing-library/react": "^16.3.0",
|
|
54
43
|
"@testing-library/user-event": "^14.6.1",
|
|
55
44
|
"@types/react": "^19.2.14",
|
|
56
45
|
"@types/react-dom": "^19.2.3",
|
|
57
46
|
"@vitejs/plugin-react": "^4.5.2",
|
|
58
|
-
"eslint": "^9.39.4",
|
|
59
|
-
"eslint-config-prettier": "^10.1.8",
|
|
60
|
-
"eslint-plugin-prettier": "^5.5.5",
|
|
61
47
|
"eslint-plugin-react-hooks": "^5.2.0",
|
|
62
|
-
"globals": "^17.4.0",
|
|
63
|
-
"husky": "^9.1.7",
|
|
64
48
|
"jsdom": "^26.1.0",
|
|
65
|
-
"lint-staged": "^16.3.3",
|
|
66
|
-
"prettier": "^3.8.1",
|
|
67
49
|
"react": "^18.3.1",
|
|
68
50
|
"react-dom": "^18.3.1",
|
|
69
|
-
"typescript": "^5.8.3",
|
|
70
|
-
"typescript-eslint": "^8.58.0",
|
|
71
51
|
"vite": "^6.3.5",
|
|
72
52
|
"vite-plugin-dts": "^4.5.4",
|
|
73
53
|
"vitest": "^3.2.3"
|
|
74
54
|
},
|
|
75
|
-
"lint-staged": {
|
|
76
|
-
"*.{ts,tsx}": "eslint --fix",
|
|
77
|
-
"*.{json,css,md}": "prettier --write"
|
|
78
|
-
},
|
|
79
55
|
"publishConfig": {
|
|
80
56
|
"access": "public"
|
|
81
57
|
},
|
|
82
|
-
"repository": {
|
|
83
|
-
"type": "git",
|
|
84
|
-
"url": "git+https://github.com/mountain-pass/addressr-react.git"
|
|
85
|
-
},
|
|
86
58
|
"keywords": [
|
|
87
59
|
"react",
|
|
88
60
|
"address",
|
|
@@ -92,5 +64,10 @@
|
|
|
92
64
|
"gnaf",
|
|
93
65
|
"combobox",
|
|
94
66
|
"hateoas"
|
|
95
|
-
]
|
|
96
|
-
|
|
67
|
+
],
|
|
68
|
+
"scripts": {
|
|
69
|
+
"build": "tsc --noEmit && vite build",
|
|
70
|
+
"test": "vitest run",
|
|
71
|
+
"lint": "eslint -c eslint.config.js src/"
|
|
72
|
+
}
|
|
73
|
+
}
|