places-autocomplete-svelte 2.2.15 → 2.2.16
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 +68 -34
- package/dist/PlaceAutocomplete.svelte +12 -16
- package/dist/gmaps.d.ts +11 -0
- package/dist/gmaps.js +23 -0
- package/dist/interfaces.d.ts +6 -0
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
[](https://badge.fury.io/js/places-autocomplete-svelte)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
A flexible, accessible, and secure [Svelte](https://kit.svelte.dev) component leveraging the [Google Maps Places Autocomplete API (New)](https://developers.google.com/maps/documentation/javascript/place-autocomplete-overview)
|
|
6
|
+
A flexible, accessible, and secure [Svelte](https://kit.svelte.dev) component leveraging the [Google Maps Places Autocomplete API (New)](https://developers.google.com/maps/documentation/javascript/place-autocomplete-overview).
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
The component handles API loading, session tokens, debounced fetching, and accessibility, allowing you to focus on building your application. It intelligently manages the Google Maps API loader, creating a shared instance that prevents conflicts with other map components on the same page.
|
|
9
9
|
|
|
10
10
|
## Available: Standalone JavaScript Library
|
|
11
11
|
|
|
@@ -15,16 +15,16 @@ Need this functionality for a non-Svelte project? Check out our companion vanill
|
|
|
15
15
|
## Features
|
|
16
16
|
|
|
17
17
|
* Integrates with the modern **Google Maps Places Autocomplete API (New)**.
|
|
18
|
+
* **Automatic Shared Loader:** Intelligently creates a single Google Maps loader instance and shares it via Svelte's context.
|
|
18
19
|
* **Highly Accessible:** Follows WAI-ARIA patterns for comboboxes, with full keyboard navigation and screen reader support.
|
|
19
20
|
* **Secure:** Safely renders suggestions to protect against XSS attacks.
|
|
20
|
-
* Automatically handles **session tokens** for cost management
|
|
21
|
+
* Automatically handles **session tokens** for cost management.
|
|
21
22
|
* **Debounced Input:** Limits API calls while the user is typing (configurable).
|
|
22
23
|
* **Suggestion Highlighting:** Automatically highlights the portion of text matching the user's input.
|
|
23
24
|
* **Imperative API:** Exposes `clear()`, `focus()`, and `getRequestParams()` methods for direct control.
|
|
24
25
|
* **Customisable Styling:** Easily override default styles using the `options.classes` prop.
|
|
25
26
|
* **TypeScript Support:** Fully written in TypeScript with included type definitions.
|
|
26
27
|
* **Event Handling:** Provides `onResponse` and `onError` callbacks.
|
|
27
|
-
* **Configurable:** Control API parameters (`requestParams`), requested data fields (`fetchFields`), and component behavior (`options`).
|
|
28
28
|
|
|
29
29
|
## Demo
|
|
30
30
|
|
|
@@ -51,45 +51,22 @@ npm install places-autocomplete-svelte
|
|
|
51
51
|
yarn add places-autocomplete-svelte
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
##
|
|
55
|
-
|
|
56
|
-
### API Key Security
|
|
57
|
-
|
|
58
|
-
Your Google Maps API Key is a sensitive credential. To prevent unauthorised use and unexpected charges, you **must** restrict it.
|
|
54
|
+
## Usage
|
|
59
55
|
|
|
60
|
-
|
|
61
|
-
2. Select your API key.
|
|
62
|
-
3. Under **Application restrictions**, select **HTTP referrers (web sites)** and add your application's domain(s) (e.g., `your-domain.com/*`).
|
|
63
|
-
4. Under **API restrictions**, select **Restrict key** and choose only the **Places API**.
|
|
64
|
-
|
|
65
|
-
### XSS Protection
|
|
66
|
-
|
|
67
|
-
This component is designed to be secure out-of-the-box. It safely renders user-input and API responses to prevent Cross-Site Scripting (XSS) vulnerabilities.
|
|
68
|
-
|
|
69
|
-
## Accessibility
|
|
70
|
-
|
|
71
|
-
This component is built to be accessible and follows the [WAI-ARIA Authoring Practices for a Combobox](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/).
|
|
72
|
-
|
|
73
|
-
* **Keyboard Navigation:** Users can navigate suggestions using `ArrowUp`, `ArrowDown`, select with `Enter`, and close the list with `Escape`.
|
|
74
|
-
* **Screen Reader Support:** Uses `role="combobox"`, `aria-autocomplete`, `aria-expanded`, and `aria-activedescendant` to provide a clear experience for screen reader users.
|
|
75
|
-
* **Focus Management:** Focus remains on the input field while navigating the suggestion list, creating a predictable experience.
|
|
76
|
-
|
|
77
|
-
## Basic Usage
|
|
78
|
-
|
|
79
|
-
1. Replace `___YOUR_API_KEY___` with your actual **Google Maps API Key**.
|
|
80
|
-
2. Use the `onResponse` callback to **handle the response**.
|
|
56
|
+
Provide your Google Maps API key to the component. It will automatically handle loading the required `places` library.
|
|
81
57
|
|
|
82
58
|
```javascript
|
|
83
|
-
<script>
|
|
59
|
+
<script lang="ts">
|
|
84
60
|
import { PlaceAutocomplete } from 'places-autocomplete-svelte';
|
|
85
61
|
import type { PlaceResult, ComponentOptions, RequestParams } from 'places-autocomplete-svelte/interfaces';
|
|
86
62
|
|
|
87
63
|
// Get API Key securely (e.g., from environment variables)
|
|
88
64
|
const PUBLIC_GOOGLE_MAPS_API_KEY = import.meta.env.VITE_PUBLIC_GOOGLE_MAPS_API_KEY;
|
|
65
|
+
|
|
66
|
+
// --- Event Handlers ---
|
|
89
67
|
let fullResponse: PlaceResult | null = $state(null);
|
|
90
68
|
let placesError = $state('');
|
|
91
69
|
|
|
92
|
-
// --- Event Handlers ---
|
|
93
70
|
const handleResponse = (response: PlaceResult) => {
|
|
94
71
|
console.log('Place Selected:', response);
|
|
95
72
|
fullResponse = response;
|
|
@@ -152,6 +129,62 @@ const options: Partial<ComponentOptions> = $state({
|
|
|
152
129
|
</style>
|
|
153
130
|
```
|
|
154
131
|
|
|
132
|
+
### Advanced: Using with other Google Maps Libraries
|
|
133
|
+
|
|
134
|
+
You can reuse the shared Google Maps loader created by the `PlaceAutocomplete` component to load other libraries (like `maps`). Because the loader instance is shared, you can access it from any other component to load additional libraries without causing conflicts.
|
|
135
|
+
|
|
136
|
+
The `PlaceAutocomplete` component only loads the `places` library by default.
|
|
137
|
+
```javascript
|
|
138
|
+
// In a parent component, e.g., src/routes/+page.svelte
|
|
139
|
+
<script lang="ts">
|
|
140
|
+
import { onMount } from 'svelte';
|
|
141
|
+
import { getGMapsLoader } from 'places-autocomplete-svelte/gmaps';
|
|
142
|
+
import PlaceAutocomplete from '$lib/PlaceAutocomplete.svelte';
|
|
143
|
+
|
|
144
|
+
const PUBLIC_GOOGLE_MAPS_API_KEY = import.meta.env.VITE_PUBLIC_GOOGLE_MAPS_API_KEY;
|
|
145
|
+
|
|
146
|
+
// Pre-initialise the loader with all libraries needed for this page.
|
|
147
|
+
onMount(async () => {
|
|
148
|
+
const loader = getGMapsLoader(PUBLIC_GOOGLE_MAPS_API_KEY);
|
|
149
|
+
const { Map } = await loader.importLibrary('maps');
|
|
150
|
+
...
|
|
151
|
+
});
|
|
152
|
+
</script>
|
|
153
|
+
|
|
154
|
+
<!-- The component will now use the loader you created above -->
|
|
155
|
+
<PlaceAutocomplete
|
|
156
|
+
{PUBLIC_GOOGLE_MAPS_API_KEY}
|
|
157
|
+
onResponse={...}
|
|
158
|
+
onError={...}
|
|
159
|
+
/>
|
|
160
|
+
|
|
161
|
+
<!-- You can now use other Google Maps services, e.g., a map -->
|
|
162
|
+
<div id="map"></div>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Security
|
|
166
|
+
|
|
167
|
+
### API Key Security
|
|
168
|
+
|
|
169
|
+
Your Google Maps API Key is a sensitive credential. To prevent unauthorised use and unexpected charges, you **must** restrict it.
|
|
170
|
+
|
|
171
|
+
1. Go to the [Google Cloud Console](https://console.cloud.google.com/google/maps-apis/credentials).
|
|
172
|
+
2. Select your API key.
|
|
173
|
+
3. Under **Application restrictions**, select **HTTP referrers (web sites)** and add your application's domain(s) (e.g., `your-domain.com/*`).
|
|
174
|
+
4. Under **API restrictions**, select **Restrict key** and choose the APIs you are using (e.g., **Places API**, **Maps JavaScript API**).
|
|
175
|
+
|
|
176
|
+
### XSS Protection
|
|
177
|
+
|
|
178
|
+
This component is designed to be secure out-of-the-box. It safely renders user-input and API responses to prevent Cross-Site Scripting (XSS) vulnerabilities.
|
|
179
|
+
|
|
180
|
+
## Accessibility
|
|
181
|
+
|
|
182
|
+
This component is built to be accessible and follows the [WAI-ARIA Authoring Practices for a Combobox](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/).
|
|
183
|
+
|
|
184
|
+
* **Keyboard Navigation:** Users can navigate suggestions using `ArrowUp`, `ArrowDown`, select with `Enter`, and close the list with `Escape`.
|
|
185
|
+
* **Screen Reader Support:** Uses `role="combobox"`, `aria-autocomplete`, `aria-expanded`, and `aria-activedescendant` to provide a clear experience for screen reader users.
|
|
186
|
+
* **Focus Management:** Focus remains on the input field while navigating the suggestion list.
|
|
187
|
+
|
|
155
188
|
## Props
|
|
156
189
|
|
|
157
190
|
| Prop | Type | Required | Default | Description |
|
|
@@ -177,7 +210,8 @@ Get a reference to the component instance using `bind:this` to call its methods
|
|
|
177
210
|
|
|
178
211
|
<PlaceAutocomplete bind:this={autocompleteComponent} ... />
|
|
179
212
|
|
|
180
|
-
<button onclick={() => autocompleteComponent
|
|
213
|
+
<button onclick={() => autocompleteComponent?.clear()}>Clear</button>
|
|
214
|
+
<button onclick={() => autocompleteComponent?.focus()}>Focus</button>
|
|
181
215
|
```
|
|
182
216
|
|
|
183
217
|
| Method | Signature | Description |
|
|
@@ -248,7 +282,7 @@ const options = {
|
|
|
248
282
|
|
|
249
283
|
## TypeScript
|
|
250
284
|
|
|
251
|
-
This component is written in TypeScript. Import types from `places-autocomplete-svelte/interfaces`.
|
|
285
|
+
This component is written in TypeScript. Import types from `places-autocomplete-svelte/interfaces` and helpers from `places-autocomplete-svelte/gmaps`.
|
|
252
286
|
|
|
253
287
|
## Google Places API & Billing
|
|
254
288
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { onMount } from 'svelte';
|
|
3
|
-
import * as GMaps from '@googlemaps/js-api-loader';
|
|
4
3
|
import type { PlaceResult, Props } from './interfaces.js';
|
|
5
4
|
import {
|
|
6
5
|
validateOptions,
|
|
@@ -10,7 +9,9 @@
|
|
|
10
9
|
createHighlightedSegments,
|
|
11
10
|
debounce
|
|
12
11
|
} from './helpers.js';
|
|
13
|
-
|
|
12
|
+
|
|
13
|
+
import { getGMapsLoader, type GMapsLoaderType } from './gmaps.js';
|
|
14
|
+
|
|
14
15
|
|
|
15
16
|
let {
|
|
16
17
|
/**
|
|
@@ -35,8 +36,6 @@
|
|
|
35
36
|
fetchFields = validateFetchFields(fetchFields);
|
|
36
37
|
//console.log(fetchFields);
|
|
37
38
|
|
|
38
|
-
// variable to hold a reference to the component's root element
|
|
39
|
-
//let componentRoot: HTMLElement;
|
|
40
39
|
|
|
41
40
|
let kbdAction = $state(''); // 'up', 'down', or 'escape'
|
|
42
41
|
|
|
@@ -44,8 +43,8 @@
|
|
|
44
43
|
let inputRef: HTMLInputElement;
|
|
45
44
|
let currentSuggestion = $state(-1);
|
|
46
45
|
let results: any[] = $state([]);
|
|
47
|
-
let loader: GMaps.Loader;
|
|
48
46
|
let placesApi: { [key: string]: any } = {};
|
|
47
|
+
let loader: GMapsLoaderType;
|
|
49
48
|
|
|
50
49
|
//https://developers.google.com/maps/documentation/javascript/reference/autocomplete-data
|
|
51
50
|
// validate requestParams
|
|
@@ -107,7 +106,6 @@
|
|
|
107
106
|
return request;
|
|
108
107
|
}
|
|
109
108
|
|
|
110
|
-
|
|
111
109
|
/**
|
|
112
110
|
* Make request and get autocomplete suggestions.
|
|
113
111
|
* @param event
|
|
@@ -225,25 +223,24 @@
|
|
|
225
223
|
inputRef.focus();
|
|
226
224
|
}
|
|
227
225
|
|
|
228
|
-
// load the Google Maps API
|
|
229
226
|
try {
|
|
230
|
-
loader =
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
227
|
+
loader = getGMapsLoader(PUBLIC_GOOGLE_MAPS_API_KEY);
|
|
228
|
+
} catch (e: any) {
|
|
229
|
+
onError(
|
|
230
|
+
(e.name || 'An error occurred') + ' - ' + (e.message || 'Error loading Google Maps API')
|
|
231
|
+
);
|
|
232
|
+
}
|
|
235
233
|
|
|
234
|
+
try {
|
|
236
235
|
const { AutocompleteSessionToken, AutocompleteSuggestion } =
|
|
237
236
|
await loader.importLibrary('places');
|
|
238
237
|
|
|
239
238
|
placesApi.AutocompleteSessionToken = AutocompleteSessionToken;
|
|
240
239
|
placesApi.AutocompleteSuggestion = AutocompleteSuggestion;
|
|
241
240
|
|
|
242
|
-
// const {Geocoder} = await loader.importLibrary("geocoding");
|
|
243
|
-
// placesApi.Geocoder = new Geocoder();
|
|
244
|
-
|
|
245
241
|
setSessionToken();
|
|
246
242
|
} catch (e: any) {
|
|
243
|
+
console.log(e);
|
|
247
244
|
onError(
|
|
248
245
|
(e.name || 'An error occurred') + ' - ' + (e.message || 'Error loading Google Maps API')
|
|
249
246
|
);
|
|
@@ -353,7 +350,6 @@
|
|
|
353
350
|
]}
|
|
354
351
|
onmouseenter={() => (currentSuggestion = i)}
|
|
355
352
|
id="option-{i + 1}"
|
|
356
|
-
|
|
357
353
|
>
|
|
358
354
|
<button
|
|
359
355
|
type="button"
|
package/dist/gmaps.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as GMaps from '@googlemaps/js-api-loader';
|
|
2
|
+
/**
|
|
3
|
+
* Defines the shape of the context object that will be shared.
|
|
4
|
+
* This can be expanded if you need to share more than just the loader.
|
|
5
|
+
*/
|
|
6
|
+
export type GMapsLoaderType = GMaps.Loader;
|
|
7
|
+
/**
|
|
8
|
+
* Gets the Google Maps Loader instance from Svelte's context.
|
|
9
|
+
* @returns {typeof Loader}
|
|
10
|
+
*/
|
|
11
|
+
export declare const getGMapsLoader: (PUBLIC_GOOGLE_MAPS_API_KEY: string, version?: string | undefined) => GMaps.Loader;
|
package/dist/gmaps.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { getContext, setContext, hasContext } from 'svelte';
|
|
2
|
+
import * as GMaps from '@googlemaps/js-api-loader';
|
|
3
|
+
const { Loader } = GMaps;
|
|
4
|
+
/**
|
|
5
|
+
* A unique key for setting and getting the Google Maps Loader instance from Svelte's context.
|
|
6
|
+
* This allows multiple components to share a single loader instance.
|
|
7
|
+
*/
|
|
8
|
+
const gmapsContextKey = Symbol('pacgmaps');
|
|
9
|
+
/**
|
|
10
|
+
* Gets the Google Maps Loader instance from Svelte's context.
|
|
11
|
+
* @returns {typeof Loader}
|
|
12
|
+
*/
|
|
13
|
+
export const getGMapsLoader = (PUBLIC_GOOGLE_MAPS_API_KEY, version) => {
|
|
14
|
+
version = version || 'weekly';
|
|
15
|
+
if (!hasContext(gmapsContextKey)) {
|
|
16
|
+
const loader = new Loader({
|
|
17
|
+
apiKey: PUBLIC_GOOGLE_MAPS_API_KEY,
|
|
18
|
+
version: version,
|
|
19
|
+
});
|
|
20
|
+
setContext(gmapsContextKey, loader);
|
|
21
|
+
}
|
|
22
|
+
return getContext(gmapsContextKey);
|
|
23
|
+
};
|
package/dist/interfaces.d.ts
CHANGED
|
@@ -48,6 +48,11 @@ export interface PlaceResult {
|
|
|
48
48
|
shortText: string;
|
|
49
49
|
types: string[];
|
|
50
50
|
}[];
|
|
51
|
+
location?: {
|
|
52
|
+
lat: number;
|
|
53
|
+
lng: number;
|
|
54
|
+
};
|
|
55
|
+
[key: string]: unknown;
|
|
51
56
|
}
|
|
52
57
|
export interface FormattedAddress {
|
|
53
58
|
street_number: string;
|
|
@@ -61,6 +66,7 @@ export interface Props {
|
|
|
61
66
|
PUBLIC_GOOGLE_MAPS_API_KEY: string;
|
|
62
67
|
options?: ComponentOptions;
|
|
63
68
|
fetchFields?: string[];
|
|
69
|
+
libraries?: string[];
|
|
64
70
|
requestParams?: RequestParams;
|
|
65
71
|
onResponse: (response: PlaceResult) => void;
|
|
66
72
|
onError: (error: string) => void;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "places-autocomplete-svelte",
|
|
3
3
|
"license": "MIT",
|
|
4
|
-
"version": "2.2.
|
|
4
|
+
"version": "2.2.16",
|
|
5
5
|
"description": "A flexible, accessible, and secure Svelte component leveraging the Google Maps Places Autocomplete API (New) to provide a user-friendly way to search for and retrieve detailed address information.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"svelte",
|
|
@@ -52,6 +52,10 @@
|
|
|
52
52
|
"svelte": "./dist/interfaces.js",
|
|
53
53
|
"default": "./dist/interfaces.js"
|
|
54
54
|
},
|
|
55
|
+
"./gmaps": {
|
|
56
|
+
"types": "./dist/gmaps.d.ts",
|
|
57
|
+
"svelte": "./dist/gmaps.js"
|
|
58
|
+
},
|
|
55
59
|
".": {
|
|
56
60
|
"types": "./dist/index.d.ts",
|
|
57
61
|
"svelte": "./dist/index.js",
|
|
@@ -80,6 +84,7 @@
|
|
|
80
84
|
"@tailwindcss/typography": "^0.5.16",
|
|
81
85
|
"@tailwindcss/vite": "^4.1.12",
|
|
82
86
|
"@types/eslint": "^9.6.1",
|
|
87
|
+
"@types/google.maps": "^3.58.1",
|
|
83
88
|
"@types/node": "^24.3.0",
|
|
84
89
|
"autoprefixer": "^10.4.21",
|
|
85
90
|
"eslint": "^9.34.0",
|