places-autocomplete-svelte 2.1.2 → 2.1.3

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 CHANGED
@@ -1,6 +1,7 @@
1
- # Places Autocomplete Svelte
1
+ # Places (New) Autocomplete Svelte
2
+
3
+ This Svelte component leverages the [Google Maps Places (New) Autocomplete API](https://developers.google.com/maps/documentation/javascript/place-autocomplete-overview) to provide a user-friendly way to search for and retrieve detailed address information within your [SvelteKit](https://kit.svelte.dev) applications. Default styling is provided using [Tailwind CSS](https://tailwindcss.com/), but you can fully customize the appearance with your own styles.
2
4
 
3
- This Svelte component leverages the [Google Maps Places Autocomplete API](https://developers.google.com/maps/documentation/javascript/place-autocomplete-overview) to provide a user-friendly way to search for and retrieve detailed address information within your [SvelteKit](https://kit.svelte.dev) applications.
4
5
 
5
6
 
6
7
  ## Features:
@@ -9,9 +10,11 @@ This Svelte component leverages the [Google Maps Places Autocomplete API](https:
9
10
  - **Autocomplete Suggestions:** Provides real-time address suggestions as the user types.
10
11
  - **Detailed Address Retrieval:** Retrieve comprehensive address information, including street address, city, region, postal code, and country.
11
12
  - **Country/Region Filtering:** Refine search results by specifying countries or regions.
12
- - **Customizable:** Tailor the component's appearance (placeholder, language) and data retrieved (`fetchFields`).
13
+ - **Customizable Appearance:** Tailor the component's look and feel with custom CSS classes, overriding the default Tailwind CSS styles.
14
+ - **Flexible Data Retrieval:** Control the retrieved data using the `fetchFields` property.
13
15
  - **Accessible:** Supports keyboard navigation for selecting suggestions.
14
16
 
17
+
15
18
  ## Demo
16
19
 
17
20
  See a live demo of the component in action: [Demo](https://places-autocomplete-demo.pages.dev/)
@@ -60,27 +63,18 @@ let onResponse = (response) => {
60
63
 
61
64
 
62
65
  ## Customization
63
-
64
- - `countries`: Use countries property to refine search by region
65
66
  - `placeholder`: Use the placeholder property to customize the input field's placeholder text.
66
67
  - `autocomplete`: Use to disable the HTML `<input>` autocomplete attribute.
67
68
  - `requestParams` (optional [AutocompleteRequest properties](https://developers.google.com/maps/documentation/javascript/reference/autocomplete-data#AutocompleteRequest) ):
68
69
  - `language`: in which to return results. If ommited defaults to `en-GB`. [See details](https://developers.google.com/maps/documentation/javascript/reference/autocomplete-data#AutocompleteRequest.language)
69
70
  - `region`: the [CLDR two-character format](https://developers.google.com/maps/documentation/javascript/reference/autocomplete-data#AutocompleteRequest). Defaults to `GB`. If the countries array is provided the coutries region overwrites the `region` value in `requestParams`.
70
71
  - `fetchFields`: Use to control the Place response. See [types](https://developers.google.com/maps/documentation/javascript/place-class-data-fields) for details. If omitted defaults to `['formattedAddress', 'addressComponents']`
72
+ - `classes`: Customize the styling by providing an object with your CSS classes. This overrides the default Tailwind CSS classes. See the example in the "Basic Usage" section for the structure of the classes object and default class names.
71
73
 
72
74
  ```svelte
73
75
  <script>
74
76
  // ... other imports
75
77
 
76
- /**
77
- * @type array optional
78
- */
79
- let countries = [
80
- { name: 'United Kingdom', region: 'GB'},
81
- { name: 'United States', region: 'US' }
82
- // ... more countries
83
- ];
84
78
  /**
85
79
  * @type string optional
86
80
  */
@@ -106,6 +100,30 @@ const requestParams = {
106
100
  region : 'GB',
107
101
  }
108
102
 
103
+ /**
104
+ * @type object optional
105
+ * Component default Tailwind CSS classes
106
+ */
107
+ const classes = {
108
+ section: '',
109
+ container: 'relative z-10 transform rounded-xl mt-4',
110
+ icon_container: 'pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3',
111
+ icon: '<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8" /><path d="m21 21-4.3-4.3" /></svg>',
112
+ input:
113
+ 'border-1 w-full rounded-md border-0 shadow-sm bg-gray-100 px-4 py-2.5 pl-10 pr-20 text-gray-900 ring-1 ring-inset ring-gray-300 focus:ring-2 sm:text-sm',
114
+ kbd_container: 'absolute inset-y-0 right-0 flex py-1.5 pr-1.5',
115
+ kbd_escape:
116
+ 'inline-flex items-center rounded border border-gray-300 px-1 font-sans text-xs text-gray-500 w-8 mr-1',
117
+ kbd_up:
118
+ 'inline-flex items-center justify-center rounded border border-gray-300 px-1 font-sans text-xs text-gray-500 w-6',
119
+ kbd_down:
120
+ 'inline-flex items-center rounded border border-gray-400 px-1 font-sans text-xs text-gray-500 justify-center w-6',
121
+ ul: 'absolute z-50 -mb-2 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm',
122
+ li: 'z-50 cursor-default select-none py-2 pl-4 text-gray-900 hover:bg-indigo-500 hover:text-white',
123
+ li_current: 'bg-indigo-500 text-white',
124
+ li_a: 'block w-full'
125
+ },
126
+
109
127
  /**
110
128
  * @type array optional
111
129
  */
@@ -120,7 +138,7 @@ const fetchFields = ['formattedAddress', 'addressComponents'];
120
138
  {placeholder}
121
139
  {autocompete}
122
140
  {fetchFields}
123
- bind:countries
141
+ {classes}
124
142
  />
125
143
 
126
144
  ```
@@ -132,11 +150,11 @@ const fetchFields = ['formattedAddress', 'addressComponents'];
132
150
  | `PUBLIC_GOOGLE_MAPS_API_KEY` | `String` | Your Google Maps Places API Key. | Yes | |
133
151
  | `onResponse` | `CustomEvent` | Dispatched when a place is selected, containing the place details. | Yes | |
134
152
  | `onError` | `CustomEvent` | Dispatched when an error occurs. | No | |
135
- | `countries` | `Array` | Array of countries/regions to filter results. | No | `[]` |
136
153
  | `placeholder` | `String` | Placeholder text for the input field. | No | `"Search..."` |
137
154
  | `autocomplete` | `string` | HTML `autocomplete` attribute for the input field. Set to "off" to disable browser autocomplete. | No | `"off"` |
138
155
  | `requestParams` | `Object` | Object for additional request parameters (e.g., `types`, `bounds`). See [AutocompleteRequest](https://developers.google.com/maps/documentation/javascript/reference/autocomplete-data#AutocompleteRequest). | No | `{}` |
139
156
  | `fetchFields` | `Array` | Array of place data fields to return. See [Supported Fields](https://developers.google.com/maps/documentation/javascript/reference/places-service#PlaceResult) | No | `['formattedAddress', 'addressComponents']` |
157
+ | `classes` | `Object` | Object to override default Tailwind CSS classes applied to the component's elements (input, list, etc.). See the "Basic Usage" section for structure and default class names. | No | *Default Tailwind classes* |
140
158
 
141
159
 
142
160
  ## Error Handling
@@ -172,6 +190,4 @@ Contributions are welcome! Please open an issue or submit a pull request on the
172
190
 
173
191
  ## License
174
192
 
175
- [MIT](LICENSE)
176
-
177
-
193
+ [MIT](LICENSE)
@@ -2,10 +2,7 @@
2
2
  import { onMount } from 'svelte';
3
3
  import * as GMaps from '@googlemaps/js-api-loader';
4
4
  import type { Props } from './interfaces.js';
5
- import {
6
- validateRequestParams,
7
- requestParamsDefault,
8
- } from './helpers.js';
5
+ import { validateRequestParams } from './helpers.js';
9
6
  const { Loader } = GMaps;
10
7
 
11
8
  let {
@@ -15,28 +12,55 @@
15
12
  */
16
13
  PUBLIC_GOOGLE_MAPS_API_KEY,
17
14
  fetchFields = $bindable(['formattedAddress', 'addressComponents']),
18
- countries = $bindable([]),
19
15
  placeholder = 'Search...',
20
16
  autocompete = 'off',
17
+ classes = {
18
+ section: '',
19
+ container: 'relative z-10 transform rounded-xl mt-4',
20
+ icon_container: 'pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3',
21
+ icon: '<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8" /><path d="m21 21-4.3-4.3" /></svg>',
22
+ input:
23
+ 'border-1 w-full rounded-md border-0 shadow-sm bg-gray-100 px-4 py-2.5 pl-10 pr-20 text-gray-900 ring-1 ring-inset ring-gray-300 focus:ring-2 sm:text-sm',
24
+ kbd_container: 'absolute inset-y-0 right-0 flex py-1.5 pr-1.5',
25
+ kbd_escape:
26
+ 'inline-flex items-center rounded border border-gray-300 px-1 font-sans text-xs text-gray-500 w-8 mr-1',
27
+ kbd_up:
28
+ 'inline-flex items-center justify-center rounded border border-gray-300 px-1 font-sans text-xs text-gray-500 w-6',
29
+ kbd_down:
30
+ 'inline-flex items-center rounded border border-gray-400 px-1 font-sans text-xs text-gray-500 justify-center w-6',
31
+ ul: 'absolute z-50 -mb-2 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm',
32
+ li: 'z-50 cursor-default select-none py-2 pl-4 text-gray-900 hover:bg-indigo-500 hover:text-white',
33
+ li_current: 'bg-indigo-500 text-white',
34
+ li_a: 'block w-full'
35
+ },
21
36
  onResponse = $bindable((e: Event) => {}),
22
37
  onError = $bindable((error: string) => {}),
23
38
  requestParams
24
39
  }: Props = $props();
25
40
 
26
- // Check if countries are available
27
- let hasCountries = countries.length > 0;
41
+ // set classes as state
42
+ let cl = $state(classes);
43
+
44
+ // reset keyboard classes
45
+ const resetKbdClasses = () => {
46
+ cl.kbd_down = classes.kbd_down;
47
+ cl.kbd_up = classes.kbd_up;
48
+ }
49
+
50
+
28
51
  // Local variables
29
52
  let inputRef: HTMLInputElement;
30
53
  let currentSuggestion = $state(-1);
31
- let title: string = $state('');
32
54
  let results: any[] = $state([]);
33
55
  let loader: GMaps.Loader;
34
56
  let placesApi: { [key: string]: any } = {};
35
57
  //https://developers.google.com/maps/documentation/javascript/reference/autocomplete-data
36
58
  // validate and merge requestParams with requestParamsDefault
37
- let request = $state(validateRequestParams(Object.assign(requestParamsDefault, requestParams)));
38
-
59
+ //let request = $state(validateRequestParams(Object.assign(requestParamsDefault, requestParams)));
60
+ requestParams = validateRequestParams(requestParams);
61
+ let request = $state(requestParams);
39
62
 
63
+ // clear result when input is empty
40
64
  $effect(() => {
41
65
  if (request.input == '') {
42
66
  results = [];
@@ -62,7 +86,7 @@
62
86
  ): Promise<void> => {
63
87
  const target = event.currentTarget as HTMLInputElement;
64
88
  if (target?.value == '') {
65
- title = '';
89
+ //title = '';
66
90
  request.input = '';
67
91
  results = [];
68
92
  return;
@@ -130,7 +154,7 @@
130
154
  request.sessionToken = new placesApi.AutocompleteSessionToken();
131
155
  } catch (e: any) {
132
156
  onError((e.name || 'An error occurred') + ' - ' + (e.message || 'error fetch token'));
133
- }
157
+ }
134
158
  };
135
159
 
136
160
  /**
@@ -165,8 +189,12 @@
165
189
  function onKeyDown(e: KeyboardEvent) {
166
190
  if (e.key === 'ArrowDown') {
167
191
  currentSuggestion = Math.min(currentSuggestion + 1, results.length - 1);
192
+ resetKbdClasses();
193
+ cl.kbd_down += ' bg-indigo-500 text-white';
168
194
  } else if (e.key === 'ArrowUp') {
169
195
  currentSuggestion = Math.max(currentSuggestion - 1, 0);
196
+ resetKbdClasses();
197
+ cl.kbd_up += ' bg-indigo-500 text-white';
170
198
  } else if (e.key === 'Enter') {
171
199
  e.preventDefault();
172
200
  if (currentSuggestion >= 0) {
@@ -176,660 +204,76 @@
176
204
  // reset srarch input and results
177
205
  reset();
178
206
  }
207
+
208
+ setTimeout(() => {
209
+ resetKbdClasses();
210
+ }, 300);
179
211
  }
180
212
  </script>
181
213
 
182
214
  <svelte:window onkeydown={onKeyDown} />
183
215
 
184
- <section class="my-10">
185
- <div class="grid grid-cols-1 lg:grid-cols-6 gap-x-4">
186
- <div class:lg:col-span-4={hasCountries} class:lg:col-span-6={!hasCountries}>
187
- <label class="mt-1 text-sm leading-6 text-gray-600" for="search"
188
- >Start typing your address</label
189
- >
190
- <div class="relative z-10 transform rounded-xl mt-4">
191
- <div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
192
- <svg
193
- xmlns="http://www.w3.org/2000/svg"
194
- class="w-5 h-5"
195
- viewBox="0 0 24 24"
196
- fill="none"
197
- stroke="currentColor"
198
- stroke-width="2"
199
- stroke-linecap="round"
200
- stroke-linejoin="round"><circle cx="11" cy="11" r="8" /><path d="m21 21-4.3-4.3" /></svg
201
- >
202
- </div>
203
-
204
- <input
205
- type="text"
206
- name="search"
207
- bind:this={inputRef}
208
- class="border-1 w-full rounded-md border-0 shadow-sm bg-gray-100 px-4 py-2.5 pl-10 pr-20 text-gray-900 ring-1 ring-inset ring-gray-300 focus:ring-2 sm:text-sm"
209
- {placeholder}
210
- autocomplete={autocompete}
211
- aria-controls="options"
212
- aria-autocomplete="list"
213
- aria-owns="options"
214
- aria-labelledby="search"
215
- aria-label="Search"
216
- aria-haspopup="listbox"
217
- bind:value={request.input}
218
- oninput={makeAcRequest}
219
- />
220
-
221
- {#if results.length > 0}
222
- <div class="absolute inset-y-0 right-0 flex py-1.5 pr-1.5">
223
- <kbd
224
- class="inline-flex items-center rounded border border-gray-300 px-1 font-sans text-xs text-gray-500 w-8 mr-1"
225
- >Esc</kbd
226
- >
227
- <kbd
228
- class="inline-flex items-center justify-center rounded border border-gray-300 px-1 font-sans text-xs text-gray-500 w-6"
229
- >&uArr;</kbd
230
- >
231
- <kbd
232
- class="inline-flex items-center rounded border border-gray-400 px-1 font-sans text-xs text-gray-500 justify-center w-6"
233
- >&dArr;</kbd
234
- >
235
- </div>
236
- <ul
237
- class="absolute z-50 -mb-2 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
238
- id="options"
239
- >
240
- {#each results as place, i}
241
- <li
242
- class="z-50 cursor-default select-none py-2 pl-4 text-gray-900 hover:bg-indigo-500 hover:text-white"
243
- class:bg-indigo-500={i === currentSuggestion}
244
- class:bg-white={i !== currentSuggestion}
245
- class:text-white={i === currentSuggestion}
246
- id="option-{i + 1}"
247
- >
248
- <!-- svelte-ignore a11y_invalid_attribute -->
249
- <a
250
- href="javascript:void(0)"
251
- class="block w-full"
252
- tabindex={i + 1}
253
- onclick={() => onPlaceSelected(place.to_pace)}
254
- >
255
- {place.text}
256
- </a>
257
- </li>
258
- {/each}
259
- </ul>
260
- {/if}
261
- </div>
216
+ <section class="{classes?.section}">
217
+ <div class="{classes.container}">
218
+ {#if classes.icon}
219
+ <div class="{classes.icon_container}">
220
+ {@html classes.icon}
262
221
  </div>
222
+ {/if}
263
223
 
264
- <div class:lg:col-span-2={hasCountries} class:hidden={!hasCountries}>
265
- <label class="mt-1 text-sm leading-6 text-gray-600" for="search">Address country</label>
266
- <div class="flex items-center mt-4">
267
- <label for="country" class="sr-only">Country</label>
268
- <select
269
- id="country"
270
- name="country"
271
- class="h-10 w-full rounded-md border-0 bg-transparent py-0 pl-2 pr-7 text-gray-500 focus:ring-2 ring-1 ring-inset ring-gray-300 focus:ring-inset focus:ring-indigo-600 sm:text-sm"
272
- bind:value={request.region}
273
- >
274
- {#each countries as country}
275
- <option value={country.region}>{country.name}</option>
276
- {/each}
277
- </select>
278
- </div>
224
+ <input
225
+ type="text"
226
+ name="search"
227
+ bind:this={inputRef}
228
+ class="{classes.input}"
229
+ {placeholder}
230
+ autocomplete={autocompete}
231
+ aria-controls="options"
232
+ aria-autocomplete="list"
233
+ aria-owns="options"
234
+ aria-labelledby="search"
235
+ aria-label="Search"
236
+ aria-haspopup="listbox"
237
+ bind:value={request.input}
238
+ oninput={makeAcRequest}
239
+ />
240
+
241
+ {#if results.length > 0}
242
+ <div class="{classes.kbd_container}">
243
+ <kbd
244
+ class="{classes.kbd_escape}"
245
+ >Esc</kbd
246
+ >
247
+ <kbd
248
+ class="{cl.kbd_up}"
249
+ >&uArr;</kbd
250
+ >
251
+ <kbd
252
+ class="{cl.kbd_down}"
253
+ >&dArr;</kbd
254
+ >
279
255
  </div>
256
+ <ul
257
+ class="{classes.ul}"
258
+ id="options"
259
+ >
260
+ {#each results as place, i}
261
+ <li
262
+ class={[ classes.li, i === currentSuggestion && classes.li_current ]}
263
+ id="option-{i + 1}"
264
+ >
265
+ <!-- svelte-ignore a11y_invalid_attribute -->
266
+ <a
267
+ href="javascript:void(0)"
268
+ class="{classes?.li_a}"
269
+ tabindex={i + 1}
270
+ onclick={() => onPlaceSelected(place.to_pace)}
271
+ >
272
+ {place.text}
273
+ </a>
274
+ </li>
275
+ {/each}
276
+ </ul>
277
+ {/if}
280
278
  </div>
281
279
  </section>
282
-
283
- <style>
284
- input,
285
- select,
286
- ul {
287
- margin: 0;
288
- padding: 0;
289
- }
290
- .absolute,
291
- .sr-only {
292
- position: absolute;
293
- }
294
- .block,
295
- svg {
296
- display: block;
297
- }
298
- *,
299
- .border-gray-300 {
300
- --tw-border-opacity: 1;
301
- }
302
- .text-gray-500,
303
- .text-gray-900,
304
- .text-white {
305
- --tw-text-opacity: 1;
306
- }
307
- *,
308
- :after,
309
- :before {
310
- box-sizing: border-box;
311
- border: 0 solid #e5e7eb;
312
- --tw-border-spacing-x: 0;
313
- --tw-border-spacing-y: 0;
314
- --tw-translate-x: 0;
315
- --tw-translate-y: 0;
316
- --tw-rotate: 0;
317
- --tw-skew-x: 0;
318
- --tw-skew-y: 0;
319
- --tw-scale-x: 1;
320
- --tw-scale-y: 1;
321
- --tw-pan-x: ;
322
- --tw-pan-y: ;
323
- --tw-pinch-zoom: ;
324
- --tw-scroll-snap-strictness: proximity;
325
- --tw-gradient-from-position: ;
326
- --tw-gradient-via-position: ;
327
- --tw-gradient-to-position: ;
328
- --tw-ordinal: ;
329
- --tw-slashed-zero: ;
330
- --tw-numeric-figure: ;
331
- --tw-numeric-spacing: ;
332
- --tw-numeric-fraction: ;
333
- --tw-ring-inset: ;
334
- --tw-ring-offset-width: 0px;
335
- --tw-ring-offset-color: #fff;
336
- --tw-ring-color: rgb(59 130 246 / 0.5);
337
- --tw-ring-offset-shadow: 0 0 #0000;
338
- --tw-ring-shadow: 0 0 #0000;
339
- --tw-shadow: 0 0 #0000;
340
- --tw-shadow-colored: 0 0 #0000;
341
- --tw-blur: ;
342
- --tw-brightness: ;
343
- --tw-contrast: ;
344
- --tw-grayscale: ;
345
- --tw-hue-rotate: ;
346
- --tw-invert: ;
347
- --tw-saturate: ;
348
- --tw-sepia: ;
349
- --tw-drop-shadow: ;
350
- --tw-backdrop-blur: ;
351
- --tw-backdrop-brightness: ;
352
- --tw-backdrop-contrast: ;
353
- --tw-backdrop-grayscale: ;
354
- --tw-backdrop-hue-rotate: ;
355
- --tw-backdrop-invert: ;
356
- --tw-backdrop-opacity: ;
357
- --tw-backdrop-saturate: ;
358
- --tw-backdrop-sepia: ;
359
- --tw-contain-size: ;
360
- --tw-contain-layout: ;
361
- --tw-contain-paint: ;
362
- --tw-contain-style: ;
363
- }
364
- :after,
365
- :before {
366
- --tw-content: '';
367
- }
368
- :host,
369
- section {
370
- line-height: 1.5;
371
- -webkit-text-size-adjust: 100%;
372
- -moz-tab-size: 4;
373
- -o-tab-size: 4;
374
- tab-size: 4;
375
- font-family:
376
- system-ui,
377
- sans-serif,
378
- apple color emoji,
379
- segoe ui emoji,
380
- Segoe UI Symbol,
381
- noto color emoji;
382
- font-feature-settings: normal;
383
- font-variation-settings: normal;
384
- -webkit-tap-highlight-color: transparent;
385
- }
386
- kbd {
387
- font-family:
388
- ui-monospace,
389
- SFMono-Regular,
390
- Menlo,
391
- Monaco,
392
- Consolas,
393
- Liberation Mono,
394
- Courier New,
395
- monospace;
396
- font-feature-settings: normal;
397
- font-variation-settings: normal;
398
- font-size: 1em;
399
- }
400
- input,
401
- select {
402
- font-family: inherit;
403
- font-feature-settings: inherit;
404
- font-variation-settings: inherit;
405
- font-size: 100%;
406
- font-weight: inherit;
407
- line-height: inherit;
408
- letter-spacing: inherit;
409
- color: inherit;
410
- }
411
- :-moz-focusring {
412
- outline: auto;
413
- }
414
- :-moz-ui-invalid {
415
- box-shadow: none;
416
- }
417
- ::-webkit-inner-spin-button,
418
- ::-webkit-outer-spin-button {
419
- height: auto;
420
- }
421
- ::-webkit-search-decoration {
422
- -webkit-appearance: none;
423
- }
424
- ::-webkit-file-upload-button {
425
- -webkit-appearance: button;
426
- font: inherit;
427
- }
428
- ul {
429
- list-style: none;
430
- }
431
- .cursor-default,
432
- :disabled {
433
- cursor: default;
434
- }
435
- svg {
436
- vertical-align: middle;
437
- }
438
- [type='text'],
439
- input:where(:not([type])),
440
- select {
441
- -webkit-appearance: none;
442
- -moz-appearance: none;
443
- appearance: none;
444
- background-color: #fff;
445
- border-color: #6b7280;
446
- border-width: 1px;
447
- border-radius: 0;
448
- padding: 0.5rem 0.75rem;
449
- font-size: 1rem;
450
- line-height: 1.5rem;
451
- --tw-shadow: 0 0 #0000;
452
- }
453
- [type='text']:focus,
454
- input:where(:not([type])):focus,
455
- select:focus {
456
- outline: transparent solid 2px;
457
- outline-offset: 2px;
458
- --tw-ring-inset: var(--tw-empty,);
459
- --tw-ring-offset-width: 0px;
460
- --tw-ring-offset-color: #fff;
461
- --tw-ring-color: #2563eb;
462
- --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
463
- var(--tw-ring-offset-color);
464
- --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width))
465
- var(--tw-ring-color);
466
- box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
467
- border-color: #2563eb;
468
- }
469
- input::-moz-placeholder {
470
- color: #6b7280;
471
- opacity: 1;
472
- }
473
- input::placeholder {
474
- color: #6b7280;
475
- opacity: 1;
476
- }
477
- select {
478
- text-transform: none;
479
- background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIGZpbGw9J25vbmUnIHZpZXdCb3g9JzAgMCAyMCAyMCc+PHBhdGggc3Ryb2tlPScjNmI3MjgwJyBzdHJva2UtbGluZWNhcD0ncm91bmQnIHN0cm9rZS1saW5lam9pbj0ncm91bmQnIHN0cm9rZS13aWR0aD0nMS41JyBkPSdNNiA4bDQgNCA0LTQnLz48L3N2Zz4=);
480
- background-position: right 0.5rem center;
481
- background-repeat: no-repeat;
482
- background-size: 1.5em 1.5em;
483
- padding-right: 2.5rem;
484
- -webkit-print-color-adjust: exact;
485
- print-color-adjust: exact;
486
- }
487
- :root {
488
- --background: 0 0% 100%;
489
- --foreground: 222.2 84% 4.9%;
490
- --muted: 210 40% 96.1%;
491
- --muted-foreground: 215.4 16.3% 46.9%;
492
- --popover: 0 0% 100%;
493
- --popover-foreground: 222.2 84% 4.9%;
494
- --card: 0 0% 100%;
495
- --card-foreground: 222.2 84% 4.9%;
496
- --border: 214.3 31.8% 91.4%;
497
- --input: 214.3 31.8% 91.4%;
498
- --primary: 222.2 47.4% 11.2%;
499
- --primary-foreground: 210 40% 98%;
500
- --secondary: 210 40% 96.1%;
501
- --secondary-foreground: 222.2 47.4% 11.2%;
502
- --accent: 210 40% 96.1%;
503
- --accent-foreground: 222.2 47.4% 11.2%;
504
- --destructive: 0 72.2% 50.6%;
505
- --destructive-foreground: 210 40% 98%;
506
- --ring: 222.2 84% 4.9%;
507
- --radius: 0.5rem;
508
- }
509
- * {
510
- border-color: hsl(var(--border) / var(--tw-border-opacity));
511
- }
512
- ::backdrop {
513
- --tw-border-spacing-x: 0;
514
- --tw-border-spacing-y: 0;
515
- --tw-translate-x: 0;
516
- --tw-translate-y: 0;
517
- --tw-rotate: 0;
518
- --tw-skew-x: 0;
519
- --tw-skew-y: 0;
520
- --tw-scale-x: 1;
521
- --tw-scale-y: 1;
522
- --tw-pan-x: ;
523
- --tw-pan-y: ;
524
- --tw-pinch-zoom: ;
525
- --tw-scroll-snap-strictness: proximity;
526
- --tw-gradient-from-position: ;
527
- --tw-gradient-via-position: ;
528
- --tw-gradient-to-position: ;
529
- --tw-ordinal: ;
530
- --tw-slashed-zero: ;
531
- --tw-numeric-figure: ;
532
- --tw-numeric-spacing: ;
533
- --tw-numeric-fraction: ;
534
- --tw-ring-inset: ;
535
- --tw-ring-offset-width: 0px;
536
- --tw-ring-offset-color: #fff;
537
- --tw-ring-color: rgb(59 130 246 / 0.5);
538
- --tw-ring-offset-shadow: 0 0 #0000;
539
- --tw-ring-shadow: 0 0 #0000;
540
- --tw-shadow: 0 0 #0000;
541
- --tw-shadow-colored: 0 0 #0000;
542
- --tw-blur: ;
543
- --tw-brightness: ;
544
- --tw-contrast: ;
545
- --tw-grayscale: ;
546
- --tw-hue-rotate: ;
547
- --tw-invert: ;
548
- --tw-saturate: ;
549
- --tw-sepia: ;
550
- --tw-drop-shadow: ;
551
- --tw-backdrop-blur: ;
552
- --tw-backdrop-brightness: ;
553
- --tw-backdrop-contrast: ;
554
- --tw-backdrop-grayscale: ;
555
- --tw-backdrop-hue-rotate: ;
556
- --tw-backdrop-invert: ;
557
- --tw-backdrop-opacity: ;
558
- --tw-backdrop-saturate: ;
559
- --tw-backdrop-sepia: ;
560
- --tw-contain-size: ;
561
- --tw-contain-layout: ;
562
- --tw-contain-paint: ;
563
- --tw-contain-style: ;
564
- }
565
- .sr-only {
566
- width: 1px;
567
- height: 1px;
568
- padding: 0;
569
- margin: -1px;
570
- overflow: hidden;
571
- clip: rect(0, 0, 0, 0);
572
- white-space: nowrap;
573
- border-width: 0;
574
- }
575
- .pointer-events-none {
576
- pointer-events: none;
577
- }
578
- .relative {
579
- position: relative;
580
- }
581
- .inset-y-0 {
582
- top: 0;
583
- bottom: 0;
584
- }
585
- .left-0 {
586
- left: 0;
587
- }
588
- .right-0 {
589
- right: 0;
590
- }
591
- .z-50 {
592
- z-index: 50;
593
- }
594
- .-mb-2 {
595
- margin-bottom: -0.5rem;
596
- }
597
- .mr-1 {
598
- margin-right: 0.25rem;
599
- }
600
- .mt-4 {
601
- margin-top: 1rem;
602
- }
603
- .flex {
604
- display: flex;
605
- }
606
- .inline-flex {
607
- display: inline-flex;
608
- }
609
- .hidden {
610
- display: none;
611
- }
612
- .h-10 {
613
- height: 2.5rem;
614
- }
615
- .h-5 {
616
- height: 1.25rem;
617
- }
618
- .max-h-60 {
619
- max-height: 15rem;
620
- }
621
- .w-5 {
622
- width: 1.25rem;
623
- }
624
- .w-6 {
625
- width: 1.5rem;
626
- }
627
- .w-8 {
628
- width: 2rem;
629
- }
630
- .w-full {
631
- width: 100%;
632
- }
633
- .transform {
634
- transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate))
635
- skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x))
636
- scaleY(var(--tw-scale-y));
637
- }
638
- .select-none {
639
- -webkit-user-select: none;
640
- -moz-user-select: none;
641
- user-select: none;
642
- }
643
- .grid-cols-1 {
644
- grid-template-columns: repeat(1, minmax(0, 1fr));
645
- grid-template-columns: 1fr;
646
- }
647
- .items-center {
648
- align-items: center;
649
- }
650
- .gap-x-4 {
651
- -moz-column-gap: 1rem;
652
- column-gap: 1rem;
653
- row-gap: 1rem;
654
- }
655
- .rounded-md {
656
- border-radius: calc(var(--radius) - 2px);
657
- }
658
- .rounded-xl {
659
- border-radius: 0.75rem;
660
- }
661
- .border {
662
- border-width: 1px;
663
- }
664
- .border-gray-300 {
665
- border-color: rgb(209 213 219 / var(--tw-border-opacity));
666
- }
667
- .bg-gray-100 {
668
- --tw-bg-opacity: 1;
669
- background-color: rgb(243 244 246 / var(--tw-bg-opacity));
670
- }
671
- .bg-indigo-500,
672
- .hover\:bg-indigo-500:hover {
673
- --tw-bg-opacity: 1;
674
- background-color: rgb(99 102 241 / var(--tw-bg-opacity));
675
- }
676
- .bg-transparent {
677
- background-color: transparent;
678
- }
679
- .bg-white {
680
- --tw-bg-opacity: 1;
681
- background-color: rgb(255 255 255 / var(--tw-bg-opacity));
682
- }
683
- .px-1 {
684
- padding-left: 0.25rem;
685
- padding-right: 0.25rem;
686
- }
687
- .px-4 {
688
- padding-left: 1rem;
689
- padding-right: 1rem;
690
- }
691
- .py-0 {
692
- padding-top: 0;
693
- padding-bottom: 0;
694
- }
695
- .py-1 {
696
- padding-top: 0.25rem;
697
- padding-bottom: 0.25rem;
698
- }
699
- .py-1\.5 {
700
- padding-top: 0.375rem;
701
- padding-bottom: 0.375rem;
702
- }
703
- .py-2 {
704
- padding-top: 0.5rem;
705
- padding-bottom: 0.5rem;
706
- }
707
- .py-2\.5 {
708
- padding-top: 0.625rem;
709
- padding-bottom: 0.625rem;
710
- }
711
- .pl-10 {
712
- padding-left: 2.5rem;
713
- }
714
- .pl-2 {
715
- padding-left: 0.5rem;
716
- }
717
- .pl-3 {
718
- padding-left: 0.75rem;
719
- }
720
- .pl-4 {
721
- padding-left: 1rem;
722
- }
723
- .pr-1\.5 {
724
- padding-right: 0.375rem;
725
- }
726
- .pr-20 {
727
- padding-right: 5rem;
728
- }
729
- .pr-7 {
730
- padding-right: 1.75rem;
731
- }
732
- .text-base {
733
- font-size: 1rem;
734
- line-height: 1.5rem;
735
- }
736
- .text-sm {
737
- font-size: 0.875rem;
738
- line-height: 1.25rem;
739
- }
740
- .text-xs {
741
- font-size: 0.75rem;
742
- line-height: 1rem;
743
- }
744
- .text-gray-500 {
745
- color: rgb(107 114 128 / var(--tw-text-opacity));
746
- }
747
- .text-gray-900 {
748
- color: rgb(17 24 39 / var(--tw-text-opacity));
749
- }
750
- .text-white {
751
- color: rgb(255 255 255 / var(--tw-text-opacity));
752
- }
753
- .shadow-lg {
754
- --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
755
- --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color),
756
- 0 4px 6px -4px var(--tw-shadow-color);
757
- box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
758
- var(--tw-shadow);
759
- }
760
- .focus\:ring-2:focus,
761
- .ring-1 {
762
- --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
763
- var(--tw-ring-offset-color);
764
- box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
765
- }
766
- .ring-1 {
767
- --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width))
768
- var(--tw-ring-color);
769
- }
770
- .ring-black {
771
- --tw-ring-opacity: 1;
772
- --tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity));
773
- }
774
- .focus\:outline-none:focus {
775
- outline: transparent solid 2px;
776
- outline-offset: 2px;
777
- }
778
- .focus\:ring-2:focus {
779
- --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width))
780
- var(--tw-ring-color);
781
- }
782
- .focus\:ring-inset:focus {
783
- --tw-ring-inset: inset;
784
- }
785
- @media (min-width: 640px) {
786
- .sm\:text-sm {
787
- font-size: 0.875rem;
788
- line-height: 1.25rem;
789
- }
790
- }
791
- @media (min-width: 1024px) {
792
- .lg\:col-span-2 {
793
- grid-column: span 2 / span 2;
794
- }
795
- }
796
- @keyframes swipe-out {
797
- 0% {
798
- transform: translateY(calc(var(--lift) * var(--offset) + var(--swipe-amount)));
799
- opacity: 1;
800
- }
801
- to {
802
- transform: translateY(
803
- calc(var(--lift) * var(--offset) + var(--swipe-amount) + var(--lift) * -100%)
804
- );
805
- opacity: 0;
806
- }
807
- }
808
- .grid {
809
- display: grid;
810
- }
811
- @media (min-width: 768px) {
812
- .lg\:grid-cols-6 {
813
- grid-template-columns: repeat(6, 1fr);
814
- }
815
- .lg\:col-span-6 {
816
- grid-column-start: span 6;
817
- }
818
- .lg\:col-span-4 {
819
- grid-column-start: span 4;
820
- }
821
- .lg\:col-span-2 {
822
- grid-column-start: span 2;
823
- }
824
- }
825
- .my-10 {
826
- margin-top: 2.5rem;
827
- margin-bottom: 2.5rem;
828
- }
829
- .justify-center {
830
- justify-content: center;
831
- }
832
- .hover\:text-white:hover {
833
- color: rgb(255 255 255 / var(--tw-text-opacity));
834
- }
835
- </style>
@@ -1,4 +1,4 @@
1
1
  import type { Props } from './interfaces.js';
2
- declare const PlaceAutocomplete: import("svelte").Component<Props, {}, "fetchFields" | "countries" | "onResponse" | "onError">;
2
+ declare const PlaceAutocomplete: import("svelte").Component<Props, {}, "fetchFields" | "onResponse" | "onError">;
3
3
  type PlaceAutocomplete = ReturnType<typeof PlaceAutocomplete>;
4
4
  export default PlaceAutocomplete;
package/dist/helpers.js CHANGED
@@ -114,6 +114,8 @@ export const validateRequestParams = (requestParams) => {
114
114
  delete requestParams[key];
115
115
  }
116
116
  }
117
+ // merge requestParams with requestParamsDefault
118
+ requestParams = Object.assign(requestParamsDefault, requestParams);
117
119
  // Reset sessionToken to empty string if passed to the component
118
120
  if (requestParams.sessionToken) {
119
121
  requestParams.sessionToken = String('');
@@ -22,6 +22,21 @@ export interface RequestParams {
22
22
  region?: string;
23
23
  sessionToken?: string;
24
24
  }
25
+ export interface ComponentClasses {
26
+ section?: string;
27
+ container?: string;
28
+ icon_container?: string;
29
+ icon?: string;
30
+ input?: string;
31
+ kbd_container?: string;
32
+ kbd_escape?: string;
33
+ kbd_up?: string;
34
+ kbd_down?: string;
35
+ ul?: string;
36
+ li?: string;
37
+ li_current?: string;
38
+ li_a?: string;
39
+ }
25
40
  export interface Props {
26
41
  PUBLIC_GOOGLE_MAPS_API_KEY: string;
27
42
  fetchFields?: string[];
@@ -30,6 +45,7 @@ export interface Props {
30
45
  region: string;
31
46
  }[];
32
47
  placeholder?: string;
48
+ classes?: ComponentClasses;
33
49
  autocompete?: AutoFill;
34
50
  requestParams: RequestParams;
35
51
  onResponse: (e: Event) => void;
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "places-autocomplete-svelte",
3
3
  "license": "MIT",
4
- "version": "2.1.2",
5
- "description": "A lightweight and customizable Svelte component for easy integration of Google Maps Places Autocomplete (New API) in your Svelte/SvelteKit applications. Provides accessible autocomplete suggestions and detailed address retrieval.",
4
+ "version": "2.1.3",
5
+ "description": "A lightweight and customizable Svelte component for easy integration of Google Maps Places (New) Autocomplete in your Svelte/SvelteKit applications. Provides accessible autocomplete suggestions and detailed address retrieval.",
6
6
  "keywords": [
7
7
  "svelte",
8
8
  "sveltekit",
@@ -68,28 +68,28 @@
68
68
  },
69
69
  "devDependencies": {
70
70
  "@sveltejs/adapter-auto": "^3.3.1",
71
- "@sveltejs/adapter-cloudflare": "^4.8.0",
72
- "@sveltejs/kit": "^2.9.0",
71
+ "@sveltejs/adapter-cloudflare": "^5.0.0",
72
+ "@sveltejs/kit": "^2.15.1",
73
73
  "@sveltejs/package": "^2.3.7",
74
- "@sveltejs/vite-plugin-svelte": "^4.0.1",
74
+ "@sveltejs/vite-plugin-svelte": "^5.0.3",
75
75
  "@tailwindcss/typography": "^0.5.15",
76
76
  "@types/eslint": "^9.6.1",
77
77
  "autoprefixer": "^10.4.20",
78
- "eslint": "^9.16.0",
78
+ "eslint": "^9.17.0",
79
79
  "eslint-config-prettier": "^9.1.0",
80
80
  "eslint-plugin-svelte": "^2.46.1",
81
- "globals": "^15.12.0",
81
+ "globals": "^15.14.0",
82
82
  "postcss": "^8.4.49",
83
- "prettier": "^3.4.1",
83
+ "prettier": "^3.4.2",
84
84
  "prettier-plugin-svelte": "^3.3.2",
85
85
  "publint": "^0.2.12",
86
- "svelte": "^5.2.11",
87
- "svelte-check": "^4.1.0",
88
- "tailwindcss": "^3.4.15",
86
+ "svelte": "^5.16.0",
87
+ "svelte-check": "^4.1.1",
88
+ "tailwindcss": "^3.4.17",
89
89
  "tslib": "^2.8.1",
90
90
  "typescript": "^5.7.2",
91
- "typescript-eslint": "^8.16.0",
92
- "vite": "^5.4.11"
91
+ "typescript-eslint": "^8.19.0",
92
+ "vite": "^6.0.6"
93
93
  },
94
94
  "svelte": "./dist/index.js",
95
95
  "types": "./dist/PlaceAutocomplete.svelte.d.ts",