places-autocomplete-svelte 2.1.7 → 2.1.8

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
@@ -69,19 +69,29 @@ let onResponse = (response) => {
69
69
 
70
70
 
71
71
  ## Component Properties
72
- | Property | Type | Description | Required | Default Value |
73
- |--------------------------|--------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|-----------------------------------------------|
74
- | `PUBLIC_GOOGLE_MAPS_API_KEY` | `String` | Your Google Maps Places API Key. | Yes | |
75
- | `onResponse` | `CustomEvent` | Dispatched when a place is selected, containing the place details. | Yes | |
76
- | `onError` | `CustomEvent` | Dispatched when an error occurs. | No | |
77
- | `placeholder` | `String` | Placeholder text for the input field. | No | `"Search..."` |
78
- | `autocomplete` | `string` | HTML `autocomplete` attribute for the input field. Set to "off" to disable browser autocomplete.
79
- | `autofocus` | `boolean` | The attribute indicating that an element should be focused on page load. | No | `false` |
80
- | `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 | `{}` |
81
- | `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']` |
82
- | `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* |
72
+
73
+ | Property | Type | Description | Required | Default Value |
74
+ |--------------------------|-----------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|-----------------------------------------------|
75
+ | `PUBLIC_GOOGLE_MAPS_API_KEY` | `String` | Your Google Maps Places API Key. | Yes | |
76
+ | `onResponse` | `CustomEvent` | Dispatched when a place is selected, containing the place details in `event.detail`. | Yes | |
77
+ | `onError` | `CustomEvent` | Dispatched when an error occurs, with the error message in `event.detail`. | No | |
78
+ | `requestParams` | `Object` | Object for additional request parameters (e.g., `types`, `bounds`, `origin`, `region`, `language`). See [AutocompleteRequest](https://developers.google.com/maps/documentation/javascript/reference/autocomplete-data#AutocompleteRequest). | No | `{}` |
79
+ | `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']` |
80
+ | `options` | `Object` | Options for customizing the component's behavior and appearance. See "Customization" below. | No | See default values in "Customization" |
81
+
82
+
83
83
 
84
84
  ## Customization
85
+ ### Options
86
+
87
+ | Property | Type | Description | Default Value |
88
+ |----------------|-----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|
89
+ | `autofocus` | `boolean` | If `true`, the input field will be focused automatically when the component mounts. | `false` |
90
+ | `placeholder` | `String` | Placeholder text for the input field. | `"Search..."` |
91
+ | `autocomplete`| `string` | HTML `autocomplete` attribute for the input field. Set to `"off"` to disable browser autocomplete. | `"off"` |
92
+ | `show_distance`| `boolean` | If `true`, and if an `origin` is specified in `requestParams`, displays the distance to each suggestion. The distance is calculated as a geodesic in meters. | `false` |
93
+ | `classes` | `Object` | Object to override default Tailwind CSS classes.structure. | See [styling](https://places-autocomplete-demo.pages.dev/examples/styling) |
94
+
85
95
  ### Styling
86
96
  Customize the component's appearance by providing an object to the classes property. This object should contain key-value pairs, where the keys correspond to the component's elements and the values are your custom CSS class names. See [styling](https://places-autocomplete-demo.pages.dev/examples/styling) for details.
87
97
 
@@ -93,17 +103,6 @@ Fine-tune the autocomplete search with the requestParams property. This property
93
103
  <script>
94
104
  // ... other imports
95
105
 
96
- /**
97
- * @type string optional
98
- */
99
- const placeholder = 'Search...';
100
- /**
101
- * @type string optional
102
- * The <input> HTML autocomplete attribute.
103
- * default: 'off'
104
- * */
105
- const autocompete = 'off';
106
-
107
106
  /**
108
107
  * @type boolean optional
109
108
  * Boolean attribute indicating that an element should be focused on page load.
@@ -127,27 +126,14 @@ const requestParams = {
127
126
 
128
127
  /**
129
128
  * @type object optional
130
- * Component default Tailwind CSS classes
129
+ * Options
131
130
  */
132
- const classes = {
133
- section: '',
134
- container: 'relative z-10 transform rounded-xl mt-4',
135
- icon_container: 'pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3',
136
- 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>',
137
- input:
138
- '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',
139
- kbd_container: 'absolute inset-y-0 right-0 flex py-1.5 pr-1.5',
140
- kbd_escape:
141
- 'inline-flex items-center rounded border border-gray-300 px-1 font-sans text-xs text-gray-500 w-8 mr-1',
142
- kbd_up:
143
- 'inline-flex items-center justify-center rounded border border-gray-300 px-1 font-sans text-xs text-gray-500 w-6',
144
- kbd_down:
145
- 'inline-flex items-center rounded border border-gray-400 px-1 font-sans text-xs text-gray-500 justify-center w-6',
146
- 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',
147
- li: 'z-50 cursor-default select-none py-2 pl-4 text-gray-900 hover:bg-indigo-500 hover:text-white',
148
- li_current: 'bg-indigo-500 text-white',
149
- li_a: 'block w-full'
150
- },
131
+ const options = {
132
+ autofocus: false,
133
+ autocompete: 'off',
134
+ placeholder: 'Start typing your address',
135
+ show_distance: true,
136
+ };
151
137
 
152
138
  /**
153
139
  * @type array optional
@@ -160,11 +146,9 @@ const fetchFields = ['formattedAddress', 'addressComponents'];
160
146
  {onResponse}
161
147
  {PUBLIC_GOOGLE_MAPS_API_KEY}
162
148
  {requestParams}
163
- {placeholder}
164
- {autocompete}
165
- {autofocus}
149
+ {options}
166
150
  {fetchFields}
167
- {classes}
151
+
168
152
  />
169
153
 
170
154
  ```
@@ -1,8 +1,8 @@
1
1
  <script lang="ts">
2
2
  import { onMount } from 'svelte';
3
3
  import * as GMaps from '@googlemaps/js-api-loader';
4
- import type { Props } from './interfaces.js';
5
- import { validateRequestParams } from './helpers.js';
4
+ import type { ComponentOptions, Props } from './interfaces.js';
5
+ import { validateOptions, validateRequestParams } from './helpers.js';
6
6
  const { Loader } = GMaps;
7
7
 
8
8
  let {
@@ -12,42 +12,38 @@
12
12
  */
13
13
  PUBLIC_GOOGLE_MAPS_API_KEY,
14
14
  fetchFields = $bindable(['formattedAddress', 'addressComponents']),
15
- placeholder = 'Search...',
16
- autocompete = 'off',
17
- autofocus = false,
18
- classes = {
19
- section: '',
20
- container: 'relative z-10 transform rounded-xl mt-4',
21
- icon_container: 'pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3',
22
- 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>',
23
- input:
24
- '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',
25
- kbd_container: 'absolute inset-y-0 right-0 flex py-1.5 pr-1.5',
26
- kbd_escape:
27
- 'inline-flex items-center rounded border border-gray-300 px-1 font-sans text-xs text-gray-500 w-8 mr-1',
28
- kbd_up:
29
- 'inline-flex items-center justify-center rounded border border-gray-300 px-1 font-sans text-xs text-gray-500 w-6',
30
- kbd_down:
31
- 'inline-flex items-center rounded border border-gray-400 px-1 font-sans text-xs text-gray-500 justify-center w-6',
32
- 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',
33
- li: 'z-50 cursor-default select-none py-2 pl-4 text-gray-900 hover:bg-indigo-500 hover:text-white',
34
- li_current: 'bg-indigo-500 text-white',
35
- li_a: 'block w-full'
36
- },
15
+ options,
37
16
  onResponse = $bindable((e: Event) => {}),
38
17
  onError = $bindable((error: string) => {}),
39
18
  requestParams = {}
40
19
  }: Props = $props();
41
20
 
21
+ // validate options
22
+ options = validateOptions(options);
23
+
42
24
  // set classes as state
43
- let cl = $state(classes);
25
+ let cl = $state(options.classes);
44
26
 
45
- // reset keyboard classes
46
- const resetKbdClasses = () => {
47
- cl.kbd_down = classes.kbd_down;
48
- cl.kbd_up = classes.kbd_up;
49
- }
27
+ // format meters to km and meters
28
+ const formatMeters = function (meters: number): string|null {
29
+ if(typeof meters !== 'number') {
30
+ return null;
31
+ }
32
+ const km = Math.floor(meters / 1000);
33
+ const remainingMeters = meters % 1000;
34
+ let formattedString = '';
35
+ if (km > 0) {
36
+ formattedString += km + 'km ';
37
+ }
38
+ formattedString += remainingMeters + 'm';
39
+ return formattedString;
40
+ };
50
41
 
42
+ // reset keyboard classes
43
+ const resetKbdClasses = () => {
44
+ cl.kbd_down = options.classes.kbd_down;
45
+ cl.kbd_up = options.classes.kbd_up;
46
+ };
51
47
 
52
48
  // Local variables
53
49
  let inputRef: HTMLInputElement;
@@ -55,12 +51,14 @@
55
51
  let results: any[] = $state([]);
56
52
  let loader: GMaps.Loader;
57
53
  let placesApi: { [key: string]: any } = {};
54
+
55
+
58
56
  //https://developers.google.com/maps/documentation/javascript/reference/autocomplete-data
59
57
  // validate and merge requestParams with requestParamsDefault
60
58
  //let request = $state(validateRequestParams(Object.assign(requestParamsDefault, requestParams)));
61
59
  requestParams = validateRequestParams(requestParams);
62
60
  let request = $state(requestParams);
63
-
61
+ //$inspect(request);
64
62
  // clear result when input is empty
65
63
  $effect(() => {
66
64
  if (request.input == '') {
@@ -108,12 +106,15 @@
108
106
  const { suggestions } =
109
107
  await placesApi.AutocompleteSuggestion.fetchAutocompleteSuggestions(request);
110
108
  results = [];
109
+ const formatter = new Intl.NumberFormat('en');
111
110
  // iterate suggestions and add results to an array
112
111
  for (const suggestion of suggestions) {
112
+
113
113
  // add suggestions to results
114
114
  results.push({
115
115
  to_pace: suggestion.placePrediction.toPlace(),
116
- text: suggestion.placePrediction.text.toString()
116
+ text: suggestion.placePrediction.text.toString(),
117
+ distance: formatMeters(suggestion.placePrediction.distanceMeters)
117
118
  });
118
119
  }
119
120
  } catch (e: any) {
@@ -162,7 +163,7 @@
162
163
  * Initialize the Google Maps JavaScript API Loader.
163
164
  */
164
165
  onMount(async (): Promise<void> => {
165
- if(autofocus) {
166
+ if (options.autofocus) {
166
167
  // focus on the input
167
168
  inputRef.focus();
168
169
  }
@@ -193,11 +194,11 @@
193
194
  if (e.key === 'ArrowDown') {
194
195
  currentSuggestion = Math.min(currentSuggestion + 1, results.length - 1);
195
196
  resetKbdClasses();
196
- cl.kbd_down += ' bg-indigo-500 text-white';
197
+ cl.kbd_down += ' bg-indigo-500 text-white';
197
198
  } else if (e.key === 'ArrowUp') {
198
199
  currentSuggestion = Math.max(currentSuggestion - 1, 0);
199
200
  resetKbdClasses();
200
- cl.kbd_up += ' bg-indigo-500 text-white';
201
+ cl.kbd_up += ' bg-indigo-500 text-white';
201
202
  } else if (e.key === 'Enter') {
202
203
  e.preventDefault();
203
204
  if (currentSuggestion >= 0) {
@@ -209,28 +210,29 @@
209
210
  }
210
211
 
211
212
  setTimeout(() => {
212
- resetKbdClasses();
213
- }, 300);
213
+ resetKbdClasses();
214
+ }, 300);
214
215
  }
215
216
  </script>
216
217
 
217
218
  <svelte:window onkeydown={onKeyDown} />
218
219
 
219
- <section class="{classes?.section}">
220
- <div class="{classes.container}">
221
- {#if classes.icon}
222
- <div class="{classes.icon_container}">
223
- {@html classes.icon}
224
- </div>
225
- {/if}
220
+ <section class={options.classes?.section}>
221
+ <div class={options.classes.container}>
222
+ {#if options.classes.icon}
223
+ <div class={options.classes.icon_container}>
224
+ {@html options.classes.icon}
225
+ </div>
226
+ {/if}
227
+
226
228
 
227
229
  <input
228
230
  type="text"
229
231
  name="search"
230
232
  bind:this={inputRef}
231
- class="{classes.input}"
232
- {placeholder}
233
- autocomplete={autocompete}
233
+ class={options.classes.input}
234
+ placeholder={options.placeholder}
235
+ autocomplete={options.autocomplete}
234
236
  aria-controls="options"
235
237
  aria-autocomplete="list"
236
238
  aria-owns="options"
@@ -242,37 +244,43 @@
242
244
  />
243
245
 
244
246
  {#if results.length > 0}
245
- <div class="{classes.kbd_container}">
246
- <kbd
247
- class="{classes.kbd_escape}"
248
- >Esc</kbd
249
- >
250
- <kbd
251
- class="{cl.kbd_up}"
252
- >&uArr;</kbd
253
- >
254
- <kbd
255
- class="{cl.kbd_down}"
256
- >&dArr;</kbd
257
- >
258
- </div>
259
- <ul
260
- class="{classes.ul}"
261
- id="options"
262
- >
247
+ <div class={options.classes.kbd_container}>
248
+ <kbd class={options.classes.kbd_escape}>Esc</kbd>
249
+ <kbd class={cl.kbd_up}>&uArr;</kbd>
250
+ <kbd class={cl.kbd_down}>&dArr;</kbd>
251
+ </div>
252
+
253
+ <ul class={options.classes.ul} id="options">
263
254
  {#each results as place, i}
264
255
  <li
265
- class={[ classes.li, i === currentSuggestion && classes.li_current ]}
256
+ class={[options.classes.li, i === currentSuggestion && options.classes.li_current]}
266
257
  id="option-{i + 1}"
267
258
  >
268
259
  <!-- svelte-ignore a11y_invalid_attribute -->
269
260
  <a
270
261
  href="javascript:void(0)"
271
- class="{classes?.li_a}"
262
+ class={[options.classes?.li_a, 'flex justify-between']}
272
263
  tabindex={i + 1}
273
264
  onclick={() => onPlaceSelected(place.to_pace)}
274
265
  >
275
- {place.text}
266
+ <div class="flex min-w-0 gap-x-4">
267
+ <!-- <img
268
+ class="size-12 flex-none rounded-full bg-gray-50"
269
+ src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
270
+ alt=""
271
+ /> -->
272
+ <div class="min-w-0 flex-auto">
273
+ <p class={[i === currentSuggestion && options.classes.li_current,'text-sm/6 font-semibold text-gray-900']}>{place.text}</p>
274
+ <!-- <p class="mt-1 truncate text-xs/5 text-gray-500">leslie.alexander@example.com</p> -->
275
+ </div>
276
+ </div>
277
+ {#if options.show_distance && place.distance}
278
+ <div class="shrink-0 flex flex-col items-end min-w-16">
279
+ <p class={[i === currentSuggestion && options.classes.li_current,'mt-1 text-xs/5 text-gray-500']}>
280
+ {place.distance}
281
+ </p>
282
+ </div>
283
+ {/if}
276
284
  </a>
277
285
  </li>
278
286
  {/each}
package/dist/helpers.d.ts CHANGED
@@ -1,7 +1,17 @@
1
- import type { RequestParams } from './interfaces.js';
1
+ import type { RequestParams, ComponentOptions, ComponentClasses } from './interfaces.js';
2
2
  export declare const requestParamsDefault: RequestParams;
3
3
  /**
4
4
  * Validate and cast request parameters
5
5
  * @param requestParams
6
6
  */
7
7
  export declare const validateRequestParams: (requestParams: RequestParams | undefined) => RequestParams;
8
+ /**
9
+ * Default component classes
10
+ */
11
+ export declare const componentClasses: ComponentClasses;
12
+ export declare const componentOptions: ComponentOptions;
13
+ /**
14
+ * Validate and cast component options
15
+ * @param options
16
+ */
17
+ export declare const validateOptions: (options: ComponentOptions | undefined) => ComponentOptions;
package/dist/helpers.js CHANGED
@@ -186,3 +186,58 @@ export const validateRequestParams = (requestParams) => {
186
186
  //console.log('requestParams:', Object.keys(requestParams));
187
187
  return requestParams;
188
188
  };
189
+ /**
190
+ * Default component classes
191
+ */
192
+ export const componentClasses = {
193
+ section: '',
194
+ container: 'relative z-10 transform rounded-xl mt-4',
195
+ icon_container: 'pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3',
196
+ 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>',
197
+ input: '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',
198
+ kbd_container: 'absolute inset-y-0 right-0 flex py-1.5 pr-1.5',
199
+ kbd_escape: 'inline-flex items-center rounded border border-gray-300 px-1 font-sans text-xs text-gray-500 w-8 mr-1',
200
+ kbd_up: 'inline-flex items-center justify-center rounded border border-gray-300 px-1 font-sans text-xs text-gray-500 w-6',
201
+ kbd_down: 'inline-flex items-center rounded border border-gray-400 px-1 font-sans text-xs text-gray-500 justify-center w-6',
202
+ 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 divide-y divide-gray-100',
203
+ li: 'z-50 cursor-default select-none py-2 px-2 lg:px-4 text-gray-900 hover:bg-indigo-500 hover:text-white',
204
+ li_current: 'bg-indigo-500 text-white',
205
+ li_a: 'block w-full',
206
+ };
207
+ export const componentOptions = {
208
+ autofocus: false,
209
+ autocomplete: 'off',
210
+ classes: componentClasses,
211
+ placeholder: '',
212
+ show_distance: false
213
+ };
214
+ /**
215
+ * Validate and cast component options
216
+ * @param options
217
+ */
218
+ export const validateOptions = (options) => {
219
+ // If options is not an object, set it to an empty object
220
+ if (typeof options !== 'object' || Object.keys(options).length === 0) {
221
+ options = {
222
+ autofocus: false,
223
+ autocomplete: 'off',
224
+ classes: componentClasses,
225
+ placeholder: 'Start typing...',
226
+ show_distance: false
227
+ };
228
+ return options;
229
+ }
230
+ // Find the missing options properties
231
+ for (const key in componentOptions) {
232
+ if (!(key in options)) {
233
+ options[key] = componentOptions[key];
234
+ }
235
+ }
236
+ // Find the missing classes properties
237
+ for (const key in componentClasses) {
238
+ if (!(key in options.classes)) {
239
+ options.classes[key] = componentClasses[key];
240
+ }
241
+ }
242
+ return options;
243
+ };
@@ -23,22 +23,18 @@ export interface RequestParams {
23
23
  sessionToken?: string;
24
24
  }
25
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;
26
+ [key: string]: string;
27
+ }
28
+ export interface ComponentOptions {
29
+ autofocus: boolean;
30
+ autocomplete: AutoFill;
31
+ classes: ComponentClasses;
32
+ placeholder: string;
33
+ show_distance: boolean;
39
34
  }
40
35
  export interface Props {
41
36
  PUBLIC_GOOGLE_MAPS_API_KEY: string;
37
+ options?: ComponentOptions;
42
38
  fetchFields?: string[];
43
39
  placeholder?: string;
44
40
  autofocus?: boolean;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "places-autocomplete-svelte",
3
3
  "license": "MIT",
4
- "version": "2.1.7",
4
+ "version": "2.1.8",
5
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",
@@ -72,9 +72,9 @@
72
72
  "@sveltejs/kit": "^2.16.1",
73
73
  "@sveltejs/package": "^2.3.9",
74
74
  "@sveltejs/vite-plugin-svelte": "^5.0.3",
75
- "@tailwindcss/postcss": "^4.0.0",
75
+ "@tailwindcss/postcss": "^4.0.3",
76
76
  "@tailwindcss/typography": "^0.5.16",
77
- "@tailwindcss/vite": "^4.0.0",
77
+ "@tailwindcss/vite": "^4.0.3",
78
78
  "@types/eslint": "^9.6.1",
79
79
  "autoprefixer": "^10.4.20",
80
80
  "eslint": "^9.19.0",
@@ -85,9 +85,9 @@
85
85
  "prettier": "^3.4.2",
86
86
  "prettier-plugin-svelte": "^3.3.3",
87
87
  "publint": "^0.3.2",
88
- "svelte": "^5.19.4",
88
+ "svelte": "^5.19.6",
89
89
  "svelte-check": "^4.1.4",
90
- "tailwindcss": "^4.0.0",
90
+ "tailwindcss": "^4.0.3",
91
91
  "tslib": "^2.8.1",
92
92
  "typescript": "^5.7.3",
93
93
  "typescript-eslint": "^8.22.0",