@maptiler/geocoding-control 0.0.44 → 0.0.48

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/dist/style.css CHANGED
@@ -1 +1 @@
1
- div.svelte-7cmwmc{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);pointer-events:none;display:flex;align-items:center}svg.svelte-7cmwmc{animation:svelte-7cmwmc-rotate .8s infinite cubic-bezier(.45,.05,.55,.95)}@keyframes svelte-7cmwmc-rotate{0%{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}svg.svelte-656hh2.svelte-656hh2{fill:#6b7c93;stroke:#6b7c93}.list-icon.svelte-656hh2.svelte-656hh2{grid-row:1/3;align-self:center;margin:8px}.in-map.svelte-656hh2.svelte-656hh2{height:30px}.for-maplibre.svelte-656hh2.svelte-656hh2{position:relative;top:-10px}.for-leaflet.svelte-656hh2.svelte-656hh2{position:relative;top:-23px;left:-50%}.maplibregl-canvas-container .marker-selected{z-index:1}.maplibregl-canvas-container svg.svelte-656hh2 path.svelte-656hh2,.leaflet-map-pane svg.svelte-656hh2 path.svelte-656hh2{fill:#3170fe;stroke:#3170fe}.marker-selected svg.svelte-656hh2 path.svelte-656hh2{fill:#98b7ff;stroke:#3170fe}svg.svelte-en2qvf{display:block;fill:var(--color-icon-button)}form.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d,form.svelte-1h1zm6d .svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d,form.svelte-1h1zm6d .svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:after,form.svelte-1h1zm6d .svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:before{box-sizing:border-box}form.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{font-family:Ubuntu,Open Sans,Helvetica Neue,Arial,Helvetica,sans-serif;position:relative;background-color:#fff;width:100%;z-index:10;border-radius:4px;transition:max-width .25s;box-shadow:0 2px 8px #33335926;--color-text:#333359;--color-icon-button:#333359}form.can-collapse.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{max-width:35px}form.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d,form.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:focus-within,form.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:hover{max-width:240px}input.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{font:inherit;font-size:14px;width:100%;border:0;background-color:transparent;margin:0;height:36px;color:#000000bf;white-space:nowrap;overflow:hidden;padding:0}input.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:focus{color:#000000bf;outline:0;outline:none;box-shadow:none}ul.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d,div.error.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d,div.no-results.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{background-color:#fff;border-radius:4px;left:0;list-style:none;margin:0;padding:0;position:absolute;width:100%;top:calc(100% + 6px);font-size:14px;box-shadow:0 2px 8px #33335926;line-height:16px;overflow:hidden}.maplibregl-ctrl-bottom-left ul.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d,.maplibregl-ctrl-bottom-right ul.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{top:auto;bottom:100%}li.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{cursor:default;display:grid;grid-template-columns:auto 1fr;color:var(--color-text);padding:4px 0}li.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:first-child{padding-top:8px}li.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:last-child{padding-bottom:8px}li.svelte-1h1zm6d>span.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{overflow:hidden;padding-right:8px}li.svelte-1h1zm6d>span.svelte-1h1zm6d>span.svelte-1h1zm6d.svelte-1h1zm6d{white-space:nowrap;display:block;min-width:fit-content}li.selected.svelte-1h1zm6d>span.svelte-1h1zm6d>span.svelte-1h1zm6d.svelte-1h1zm6d{animation:svelte-1h1zm6d-backAndForth 5s linear infinite}li.svelte-1h1zm6d>span.svelte-1h1zm6d:nth-of-type(1)>span.svelte-1h1zm6d>span.svelte-1h1zm6d:nth-of-type(1){font-weight:700}li.svelte-1h1zm6d>span.svelte-1h1zm6d:nth-of-type(1)>span.svelte-1h1zm6d>span.svelte-1h1zm6d:nth-of-type(2){color:#aeb6c7;font-size:12px;padding-left:4px}li.selected.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{background-color:#f3f3f3}button.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:hover{background-color:transparent}button.svelte-1h1zm6d:hover svg,button.active.svelte-1h1zm6d svg{fill:#6b7c92}button.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{padding:0;margin:0;border:0;background-color:transparent}.input-group.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{display:flex;align-items:stretch;gap:7px;padding-inline:8px;outline:#c1cfe4 solid 2px;border-radius:4px;overflow:hidden}.input-group.svelte-1h1zm6d:hover .displayable.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{visibility:visible}.input-group.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:focus-within{outline:#3170fe solid 2px}div.error.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d,div.no-results.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{font:inherit;font-size:14px;padding:6px 10px}div.error.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{color:#e25041}div.no-results.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{color:var(--color-text)}.clear-button-container.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{position:relative;display:flex;align-items:stretch}.clear-button-container.svelte-1h1zm6d button.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{visibility:hidden}@keyframes svelte-1h1zm6d-backAndForth{0%{transform:translate(0)}10%{transform:translate(0)}45%{transform:translate(calc(-100% + 196px))}55%{transform:translate(calc(-100% + 196px))}90%{transform:translate(0)}to{transform:translate(0)}}form.can-collapse.svelte-1h1zm6d button.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:not(:nth-of-type(1)){opacity:0;transition:opacity .25s}form.can-collapse.svelte-1h1zm6d:focus-within .svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:not(:nth-of-type(1)),form.can-collapse.svelte-1h1zm6d:hover .svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:not(:nth-of-type(1)){opacity:1}
1
+ div.svelte-7cmwmc{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);pointer-events:none;display:flex;align-items:center}svg.svelte-7cmwmc{animation:svelte-7cmwmc-rotate .8s infinite cubic-bezier(.45,.05,.55,.95)}@keyframes svelte-7cmwmc-rotate{0%{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}svg.svelte-edyshv.svelte-edyshv{display:block;fill:#6b7c93;stroke:#6b7c93}.list-icon.svelte-edyshv.svelte-edyshv{grid-row:1/3;align-self:center;margin:8px}.in-map.svelte-edyshv.svelte-edyshv{height:30px}.maplibregl-canvas-container .marker-selected{z-index:1}.maplibregl-canvas-container svg.svelte-edyshv path.svelte-edyshv,.leaflet-map-pane svg.svelte-edyshv path.svelte-edyshv{fill:#3170fe;stroke:#3170fe}.marker-selected svg.svelte-edyshv path.svelte-edyshv{fill:#98b7ff;stroke:#3170fe}.marker-reverse svg.svelte-edyshv path.svelte-edyshv{fill:silver;stroke:gray}.marker-interactive{cursor:pointer!important}.marker-fuzzy svg.svelte-edyshv path.svelte-edyshv{fill:silver;stroke:gray}.marker-fuzzy.marker-selected svg.svelte-edyshv path.svelte-edyshv{fill:#ddd;stroke:silver}svg.svelte-en2qvf{display:block;fill:var(--color-icon-button)}form.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d,form.svelte-1h1zm6d .svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d,form.svelte-1h1zm6d .svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:after,form.svelte-1h1zm6d .svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:before{box-sizing:border-box}form.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{font-family:Ubuntu,Open Sans,Helvetica Neue,Arial,Helvetica,sans-serif;position:relative;background-color:#fff;width:100%;z-index:10;border-radius:4px;transition:max-width .25s;box-shadow:0 2px 8px #33335926;--color-text:#333359;--color-icon-button:#333359}form.can-collapse.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{max-width:35px}form.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d,form.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:focus-within,form.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:hover{max-width:240px}input.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{font:inherit;font-size:14px;width:100%;border:0;background-color:transparent;margin:0;height:36px;color:#000000bf;white-space:nowrap;overflow:hidden;padding:0}input.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:focus{color:#000000bf;outline:0;outline:none;box-shadow:none}ul.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d,div.error.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d,div.no-results.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{background-color:#fff;border-radius:4px;left:0;list-style:none;margin:0;padding:0;position:absolute;width:100%;top:calc(100% + 6px);font-size:14px;box-shadow:0 2px 8px #33335926;line-height:16px;overflow:hidden}.maplibregl-ctrl-bottom-left ul.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d,.maplibregl-ctrl-bottom-right ul.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{top:auto;bottom:100%}li.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{cursor:default;display:grid;grid-template-columns:auto 1fr;color:var(--color-text);padding:4px 0}li.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:first-child{padding-top:8px}li.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:last-child{padding-bottom:8px}li.svelte-1h1zm6d>span.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{overflow:hidden;padding-right:8px}li.svelte-1h1zm6d>span.svelte-1h1zm6d>span.svelte-1h1zm6d.svelte-1h1zm6d{white-space:nowrap;display:block;min-width:fit-content}li.selected.svelte-1h1zm6d>span.svelte-1h1zm6d>span.svelte-1h1zm6d.svelte-1h1zm6d{animation:svelte-1h1zm6d-backAndForth 5s linear infinite}li.svelte-1h1zm6d>span.svelte-1h1zm6d:nth-of-type(1)>span.svelte-1h1zm6d>span.svelte-1h1zm6d:nth-of-type(1){font-weight:700}li.svelte-1h1zm6d>span.svelte-1h1zm6d:nth-of-type(1)>span.svelte-1h1zm6d>span.svelte-1h1zm6d:nth-of-type(2){color:#aeb6c7;font-size:12px;padding-left:4px}li.selected.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{background-color:#f3f3f3}button.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:hover{background-color:transparent}button.svelte-1h1zm6d:hover svg,button.active.svelte-1h1zm6d svg{fill:#6b7c92}button.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{padding:0;margin:0;border:0;background-color:transparent}.input-group.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{display:flex;align-items:stretch;gap:7px;padding-inline:8px;outline:#c1cfe4 solid 2px;border-radius:4px;overflow:hidden}.input-group.svelte-1h1zm6d:hover .displayable.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{visibility:visible}.input-group.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:focus-within{outline:#3170fe solid 2px}div.error.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d,div.no-results.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{font:inherit;font-size:14px;padding:6px 10px}div.error.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{color:#e25041}div.no-results.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{color:var(--color-text)}.clear-button-container.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{position:relative;display:flex;align-items:stretch}.clear-button-container.svelte-1h1zm6d button.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d{visibility:hidden}@keyframes svelte-1h1zm6d-backAndForth{0%{transform:translate(0)}10%{transform:translate(0)}45%{transform:translate(calc(-100% + 196px))}55%{transform:translate(calc(-100% + 196px))}90%{transform:translate(0)}to{transform:translate(0)}}form.can-collapse.svelte-1h1zm6d button.svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:not(:nth-of-type(1)){opacity:0;transition:opacity .25s}form.can-collapse.svelte-1h1zm6d:focus-within .svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:not(:nth-of-type(1)),form.can-collapse.svelte-1h1zm6d:hover .svelte-1h1zm6d.svelte-1h1zm6d.svelte-1h1zm6d:not(:nth-of-type(1)){opacity:1}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maptiler/geocoding-control",
3
- "version": "0.0.44",
3
+ "version": "0.0.48",
4
4
  "type": "module",
5
5
  "author": {
6
6
  "name": "Martin Ždila",
@@ -43,24 +43,24 @@
43
43
  },
44
44
  "types": "./dist/lib/index.d.ts",
45
45
  "devDependencies": {
46
- "@sveltejs/vite-plugin-svelte": "^1.3.1",
46
+ "@sveltejs/vite-plugin-svelte": "^2.0.2",
47
47
  "@tsconfig/svelte": "^3.0.0",
48
48
  "@turf/buffer": "^6.5.0",
49
49
  "@turf/difference": "^6.5.0",
50
50
  "@turf/union": "^6.5.0",
51
51
  "@types/leaflet": "^1.9.0",
52
- "prettier": "^2.8.0",
53
- "prettier-plugin-svelte": "^2.8.1",
54
- "svelte": "^3.53.1",
55
- "svelte-check": "^2.9.2",
56
- "svelte-preprocess": "^4.10.7",
52
+ "prettier": "^2.8.1",
53
+ "prettier-plugin-svelte": "^2.9.0",
54
+ "svelte": "^3.55.0",
55
+ "svelte-check": "^2.10.2",
56
+ "svelte-preprocess": "^5.0.0",
57
57
  "tslib": "^2.4.1",
58
- "typescript": "^4.9.3",
59
- "vite": "^3.2.4"
58
+ "typescript": "^4.9.4",
59
+ "vite": "^4.0.2"
60
60
  },
61
61
  "peerDependencies": {
62
- "leaflet": "^1.9.2",
63
- "maplibre-gl": "> 1.14.0"
62
+ "leaflet": "^1.9.3",
63
+ "maplibre-gl": "^2.4.0"
64
64
  },
65
65
  "peerDependenciesMeta": {
66
66
  "leaflet": {
@@ -1,4 +1,4 @@
1
- <script type="ts">
1
+ <script lang="ts">
2
2
  import { createEventDispatcher } from "svelte";
3
3
  import { onDestroy } from "svelte/internal";
4
4
  import ReverseGeocodingIcon from "./ReverseGeocodingIcon.svelte";
@@ -37,7 +37,7 @@
37
37
 
38
38
  export let minLength = 2;
39
39
 
40
- export let language: string | undefined = undefined;
40
+ export let language: string | string[] | undefined = undefined;
41
41
 
42
42
  export let showResultsWhileTyping = true;
43
43
 
@@ -65,11 +65,13 @@
65
65
 
66
66
  export let showFullGeometry = true;
67
67
 
68
- // export let limit = 5;
68
+ export let limit: number | undefined = undefined;
69
69
 
70
- // export let autocomplete = true;
70
+ export let fuzzyMatch = true;
71
71
 
72
- // export let fuzzy = true;
72
+ export let countries: string | string[] | undefined = undefined;
73
+
74
+ export let types: string[] | undefined = undefined;
73
75
 
74
76
  export function focus() {
75
77
  input.focus();
@@ -116,7 +118,7 @@
116
118
 
117
119
  let abortController: AbortController | undefined;
118
120
 
119
- let searchTimeoutRef: number;
121
+ let searchTimeoutRef: number | undefined;
120
122
 
121
123
  let focusedDelayed: boolean;
122
124
 
@@ -131,16 +133,6 @@
131
133
  queryChange: string;
132
134
  }>();
133
135
 
134
- $: if (mapController) {
135
- mapController.setProximityChangeHandler(
136
- trackProximity
137
- ? (p) => {
138
- proximity = p;
139
- }
140
- : undefined
141
- );
142
- }
143
-
144
136
  $: if (!trackProximity) {
145
137
  proximity = undefined;
146
138
  }
@@ -151,7 +143,7 @@
151
143
  !picked.address &&
152
144
  picked.geometry.type === "Point"
153
145
  ) {
154
- search(picked.id, true).catch((err) => (error = err));
146
+ search(picked.id, { byId: true }).catch((err) => (error = err));
155
147
  }
156
148
 
157
149
  $: if (mapController && picked && flyTo) {
@@ -205,6 +197,14 @@
205
197
 
206
198
  $: selected = listFeatures?.[selectedItemIndex];
207
199
 
200
+ $: {
201
+ const m = /^(-?\d+(?:\.\d*)?),(-?\d+(?:\.\d*)?)$/.exec(searchValue);
202
+
203
+ mapController?.setReverseMarker(
204
+ m ? [Number(m[1]), Number(m[2])] : undefined
205
+ );
206
+ }
207
+
208
208
  $: dispatch("select", selected);
209
209
 
210
210
  $: dispatch("pick", picked);
@@ -224,13 +224,47 @@
224
224
  }
225
225
 
226
226
  $: if (mapController) {
227
- mapController.setMapClickHandler(reverseActive ? handleReverse : undefined);
227
+ mapController.setEventHandler((e) => {
228
+ switch (e.type) {
229
+ case "mapClick":
230
+ if (reverseActive) {
231
+ handleReverse(e.coordinates);
232
+ }
233
+
234
+ break;
235
+ case "proximityChange":
236
+ proximity = trackProximity ? e.proximity : undefined;
237
+
238
+ break;
239
+ case "markerClick":
240
+ {
241
+ const feature = listFeatures?.find(
242
+ (feature) => feature.id === e.id
243
+ );
244
+
245
+ if (feature) {
246
+ pick(feature);
247
+ }
248
+ }
249
+
250
+ break;
251
+ case "markerMouseEnter":
252
+ selectedItemIndex = !focusedDelayed
253
+ ? -1
254
+ : listFeatures?.findIndex((feature) => feature.id === e.id) ?? -1;
255
+
256
+ break;
257
+ case "markerMouseLeave":
258
+ selectedItemIndex = -1;
259
+
260
+ break;
261
+ }
262
+ });
228
263
  }
229
264
 
230
265
  onDestroy(() => {
231
266
  if (mapController) {
232
- mapController.setProximityChangeHandler(undefined);
233
- mapController.setMapClickHandler(undefined);
267
+ mapController.setEventHandler(undefined);
234
268
  mapController.indicateReverse(false);
235
269
  mapController.setSelectedMarker(-1);
236
270
  mapController.setMarkers(undefined, undefined);
@@ -238,6 +272,12 @@
238
272
  });
239
273
 
240
274
  function handleOnSubmit(event?: unknown) {
275
+ if (searchTimeoutRef) {
276
+ clearTimeout(searchTimeoutRef);
277
+
278
+ searchTimeoutRef = undefined;
279
+ }
280
+
241
281
  if (selectedItemIndex > -1 && listFeatures) {
242
282
  picked = listFeatures[selectedItemIndex];
243
283
  searchValue = picked.place_name.replace(/,.*/, "");
@@ -247,7 +287,7 @@
247
287
  } else if (searchValue) {
248
288
  const zoomTo = event || !isQuerReverse();
249
289
 
250
- search(searchValue)
290
+ search(searchValue, { exact: true })
251
291
  .then(() => {
252
292
  markedFeatures = listFeatures;
253
293
 
@@ -265,7 +305,13 @@
265
305
  return /^-?\d+(\.\d+)?,-?\d+(\.\d+)?$/.test(searchValue);
266
306
  }
267
307
 
268
- async function search(searchValue: string, byId = false) {
308
+ async function search(
309
+ searchValue: string,
310
+ {
311
+ byId = false,
312
+ exact = false,
313
+ }: undefined | { byId?: boolean; exact?: boolean } = {}
314
+ ) {
269
315
  error = undefined;
270
316
 
271
317
  const isReverse = isQuerReverse();
@@ -273,7 +319,21 @@
273
319
  const sp = new URLSearchParams();
274
320
 
275
321
  if (language) {
276
- sp.set("language", String(language));
322
+ sp.set(
323
+ "language",
324
+ Array.isArray(language) ? language.join(",") : language
325
+ );
326
+ }
327
+
328
+ if (countries) {
329
+ sp.set(
330
+ "stack",
331
+ Array.isArray(countries) ? countries.join(",") : countries
332
+ );
333
+ }
334
+
335
+ if (types) {
336
+ sp.set("types", types.join(","));
277
337
  }
278
338
 
279
339
  if (!isReverse) {
@@ -285,12 +345,16 @@
285
345
  sp.set("proximity", proximity.map((c) => c.toFixed(6)).join(","));
286
346
  }
287
347
 
288
- // sp.set("autocomplete", String(autocomplete));
348
+ if (exact || !showResultsWhileTyping) {
349
+ sp.set("autocomplete", "false");
350
+ }
289
351
 
290
- // sp.set("fuzzyMatch", String(fuzzy));
352
+ sp.set("fuzzyMatch", String(fuzzyMatch));
291
353
  }
292
354
 
293
- // sp.set("limit", String(limit));
355
+ if (limit !== undefined) {
356
+ sp.set("limit", String(limit));
357
+ }
294
358
 
295
359
  sp.set("key", apiKey);
296
360
 
@@ -365,11 +429,15 @@
365
429
 
366
430
  const bbox: [number, number, number, number] = [180, 90, -180, -90];
367
431
 
432
+ const fuzzyOnly = !markedFeatures.some((feature) => !feature.matching_text);
433
+
368
434
  for (const feature of markedFeatures) {
369
- bbox[0] = Math.min(bbox[0], feature.bbox?.[0] ?? feature.center[0]);
370
- bbox[1] = Math.min(bbox[1], feature.bbox?.[1] ?? feature.center[1]);
371
- bbox[2] = Math.max(bbox[2], feature.bbox?.[2] ?? feature.center[0]);
372
- bbox[3] = Math.max(bbox[3], feature.bbox?.[3] ?? feature.center[1]);
435
+ if (fuzzyOnly || !feature.matching_text) {
436
+ bbox[0] = Math.min(bbox[0], feature.bbox?.[0] ?? feature.center[0]);
437
+ bbox[1] = Math.min(bbox[1], feature.bbox?.[1] ?? feature.center[1]);
438
+ bbox[2] = Math.max(bbox[2], feature.bbox?.[2] ?? feature.center[0]);
439
+ bbox[3] = Math.max(bbox[3], feature.bbox?.[3] ?? feature.center[1]);
440
+ }
373
441
  }
374
442
 
375
443
  if (mapController && markedFeatures.length > 0) {
@@ -382,11 +450,7 @@
382
450
  }
383
451
 
384
452
  // taken from Leaflet
385
- export function wrapNum(
386
- x: number,
387
- range: [number, number],
388
- includeMax: boolean
389
- ) {
453
+ function wrapNum(x: number, range: [number, number], includeMax: boolean) {
390
454
  const max = range[1],
391
455
  min = range[0],
392
456
  d = max - min;
@@ -447,6 +511,12 @@
447
511
  error = undefined;
448
512
  }
449
513
  }
514
+
515
+ function pick(feature: Feature) {
516
+ picked = feature;
517
+ searchValue = feature.place_name.replace(/,.*/, "");
518
+ selectedItemIndex = -1;
519
+ }
450
520
  </script>
451
521
 
452
522
  <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
@@ -519,11 +589,7 @@
519
589
  data-selected={selectedItemIndex === i}
520
590
  class:selected={selectedItemIndex === i}
521
591
  on:mouseover={() => (selectedItemIndex = i)}
522
- on:focus={() => {
523
- picked = feature;
524
- searchValue = feature.place_name.replace(/,.*/, "");
525
- selectedItemIndex = -1;
526
- }}
592
+ on:focus={() => pick(feature)}
527
593
  >
528
594
  <MarkerIcon displayIn="list" />
529
595
  <span>
@@ -1,4 +1,4 @@
1
- <script type="ts">
1
+ <script lang="ts">
2
2
  export let displayIn: "list" | "leaflet" | "maplibre";
3
3
  </script>
4
4
 
@@ -7,8 +7,6 @@
7
7
  viewBox="0 0 70 85"
8
8
  fill="none"
9
9
  class:in-map={displayIn !== "list"}
10
- class:for-maplibre={displayIn === "maplibre"}
11
- class:for-leaflet={displayIn === "leaflet"}
12
10
  class:list-icon={displayIn === "list"}
13
11
  >
14
12
  <path
@@ -21,6 +19,7 @@
21
19
 
22
20
  <style>
23
21
  svg {
22
+ display: block;
24
23
  fill: #6b7c93;
25
24
  stroke: #6b7c93;
26
25
  }
@@ -35,17 +34,6 @@
35
34
  height: 30px;
36
35
  }
37
36
 
38
- .for-maplibre {
39
- position: relative;
40
- top: -10px;
41
- }
42
-
43
- .for-leaflet {
44
- position: relative;
45
- top: -23px;
46
- left: -50%;
47
- }
48
-
49
37
  :global(.maplibregl-canvas-container .marker-selected) {
50
38
  z-index: 1;
51
39
  }
@@ -60,4 +48,23 @@
60
48
  fill: #98b7ff;
61
49
  stroke: #3170fe;
62
50
  }
51
+
52
+ :global(.marker-reverse) svg path {
53
+ fill: silver;
54
+ stroke: gray;
55
+ }
56
+
57
+ :global(.marker-interactive) {
58
+ cursor: pointer !important;
59
+ }
60
+
61
+ :global(.marker-fuzzy) svg path {
62
+ fill: silver;
63
+ stroke: gray;
64
+ }
65
+
66
+ :global(.marker-fuzzy.marker-selected) svg path {
67
+ fill: #ddd;
68
+ stroke: silver;
69
+ }
63
70
  </style>
@@ -1,6 +1,6 @@
1
1
  import * as L from "leaflet";
2
2
  import MarkerIcon from "./MarkerIcon.svelte";
3
- import type { Feature, MapController, Proximity } from "./types";
3
+ import type { Feature, MapController, MapEvent, Proximity } from "./types";
4
4
  import type {
5
5
  Polygon,
6
6
  MultiPolygon,
@@ -35,9 +35,7 @@ export function createLeafletMapController(
35
35
  };
36
36
  }
37
37
  ) {
38
- let proximityChangeHandler: ((proximity: Proximity) => void) | undefined;
39
-
40
- let mapClickHandler: ((coordinates: [number, number]) => void) | undefined;
38
+ let eventHandler: ((e: MapEvent) => void) | undefined;
41
39
 
42
40
  let prevProximity: Proximity = undefined;
43
41
 
@@ -45,17 +43,14 @@ export function createLeafletMapController(
45
43
 
46
44
  let selectedMarker: L.Marker | undefined;
47
45
 
46
+ let reverseMarker: L.Marker | undefined;
47
+
48
48
  let resultLayer = L.geoJSON(undefined, {
49
49
  style: fullGeometryStyle,
50
+ interactive: false,
50
51
  }).addTo(map);
51
52
 
52
53
  const handleMoveEnd = () => {
53
- if (!proximityChangeHandler) {
54
- prevProximity = undefined;
55
-
56
- return;
57
- }
58
-
59
54
  let c: L.LatLng;
60
55
 
61
56
  const proximity =
@@ -66,47 +61,55 @@ export function createLeafletMapController(
66
61
  if (prevProximity !== proximity) {
67
62
  prevProximity = proximity;
68
63
 
69
- proximityChangeHandler(proximity);
64
+ eventHandler?.({ type: "proximityChange", proximity });
70
65
  }
71
66
  };
72
67
 
73
68
  const handleMapClick = (e: L.LeafletMouseEvent) => {
74
- mapClickHandler?.([e.latlng.lng, e.latlng.lat]);
69
+ eventHandler?.({
70
+ type: "mapClick",
71
+ coordinates: [e.latlng.lng, e.latlng.lat],
72
+ });
75
73
  };
76
74
 
75
+ function createMarker(pos: L.LatLngExpression, interactive = false) {
76
+ const element = document.createElement("div");
77
+
78
+ new MarkerIcon({ props: { displayIn: "leaflet" }, target: element });
79
+
80
+ return new L.Marker(pos, {
81
+ interactive,
82
+ icon: new L.DivIcon({
83
+ html: element,
84
+ className: "",
85
+ iconAnchor: [12, 26],
86
+ }),
87
+ });
88
+ }
89
+
77
90
  const ctrl: MapController = {
78
- setProximityChangeHandler(
79
- _proximityChangeHandler: ((proximity: Proximity) => void) | undefined
80
- ): void {
81
- if (_proximityChangeHandler) {
82
- proximityChangeHandler = _proximityChangeHandler;
91
+ setEventHandler(handler: undefined | ((e: MapEvent) => void)): void {
92
+ if (handler) {
93
+ eventHandler = handler;
83
94
 
84
95
  map.on("moveend", handleMoveEnd);
85
96
 
86
97
  handleMoveEnd();
98
+
99
+ map.on("click", handleMapClick);
87
100
  } else {
88
101
  map.off("moveend", handleMoveEnd);
89
102
 
90
- proximityChangeHandler?.(undefined);
103
+ eventHandler?.({ type: "proximityChange", proximity: undefined });
91
104
 
92
- proximityChangeHandler = undefined;
93
- }
94
- },
95
-
96
- setMapClickHandler(
97
- _mapClickHandler: ((coordinates: [number, number]) => void) | undefined
98
- ): void {
99
- mapClickHandler = _mapClickHandler;
105
+ eventHandler = undefined;
100
106
 
101
- if (mapClickHandler) {
102
- map.on("click", handleMapClick);
103
- } else {
104
107
  map.off("click", handleMapClick);
105
108
  }
106
109
  },
107
110
 
108
111
  flyTo(center: [number, number], zoom: number) {
109
- map.flyTo(center, zoom, { duration: 2, ...flyToOptions });
112
+ map.flyTo([center[1], center[0]], zoom, { duration: 2, ...flyToOptions });
110
113
  },
111
114
 
112
115
  fitBounds(bbox: [number, number, number, number], padding: number): void {
@@ -123,10 +126,41 @@ export function createLeafletMapController(
123
126
  map.getContainer().style.cursor = reverse ? "crosshair" : "";
124
127
  },
125
128
 
129
+ setReverseMarker(coordinates: [number, number]) {
130
+ if (!marker) {
131
+ return;
132
+ }
133
+
134
+ const latLng =
135
+ coordinates && ([coordinates[1], coordinates[0]] as [number, number]);
136
+
137
+ if (reverseMarker) {
138
+ if (!latLng) {
139
+ reverseMarker.remove();
140
+
141
+ reverseMarker = undefined;
142
+ } else {
143
+ reverseMarker.setLatLng(latLng);
144
+ }
145
+ } else if (latLng) {
146
+ reverseMarker = (
147
+ typeof marker === "object"
148
+ ? new L.Marker(latLng, marker)
149
+ : createMarker(latLng)
150
+ ).addTo(map);
151
+
152
+ reverseMarker.getElement()?.classList.add("marker-reverse");
153
+ }
154
+ },
155
+
126
156
  setMarkers(
127
157
  markedFeatures: Feature[] | undefined,
128
158
  picked: Feature | undefined
129
159
  ): void {
160
+ if (!marker) {
161
+ return;
162
+ }
163
+
130
164
  function setData(data?: GeoJSON.GeoJSON) {
131
165
  resultLayer.clearLayers();
132
166
 
@@ -143,16 +177,6 @@ export function createLeafletMapController(
143
177
 
144
178
  setData();
145
179
 
146
- const createMarker = (pos: L.LatLngExpression) => {
147
- const element = document.createElement("div");
148
-
149
- new MarkerIcon({ props: { displayIn: "leaflet" }, target: element });
150
-
151
- return new L.Marker(pos, {
152
- icon: new L.DivIcon({ html: element, className: "" }),
153
- });
154
- };
155
-
156
180
  if (picked) {
157
181
  let handled = false;
158
182
 
@@ -218,19 +242,46 @@ export function createLeafletMapController(
218
242
  );
219
243
  }
220
244
 
221
- for (const feature of markedFeatures ?? []) {
222
- if (feature === picked) {
223
- continue;
224
- }
245
+ if (showResultMarkers) {
246
+ for (const feature of markedFeatures ?? []) {
247
+ if (feature === picked) {
248
+ continue;
249
+ }
225
250
 
226
- const pos: L.LatLngExpression = [feature.center[1], feature.center[0]];
251
+ const pos: L.LatLngExpression = [
252
+ feature.center[1],
253
+ feature.center[0],
254
+ ];
227
255
 
228
- markers.push(
229
- (typeof showResultMarkers === "object"
230
- ? new L.Marker(pos, showResultMarkers)
231
- : createMarker(pos)
232
- ).addTo(map)
233
- );
256
+ const marker =
257
+ typeof showResultMarkers === "object"
258
+ ? new L.Marker(pos, showResultMarkers)
259
+ : createMarker(pos, true);
260
+
261
+ marker.addTo(map);
262
+
263
+ const element = marker.getElement();
264
+
265
+ if (element) {
266
+ element.addEventListener("click", (e) => {
267
+ e.stopPropagation();
268
+
269
+ eventHandler?.({ type: "markerClick", id: feature.id });
270
+ });
271
+
272
+ element.addEventListener("mouseenter", () => {
273
+ eventHandler?.({ type: "markerMouseEnter", id: feature.id });
274
+ });
275
+
276
+ element.addEventListener("mouseleave", () => {
277
+ eventHandler?.({ type: "markerMouseLeave", id: feature.id });
278
+ });
279
+
280
+ element.classList.toggle("marker-fuzzy", !!feature.matching_text);
281
+ }
282
+
283
+ markers.push(marker);
284
+ }
234
285
  }
235
286
  },
236
287