@maptiler/geocoding-control 0.0.44 → 0.0.52

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-1k1cmht.svelte-1k1cmht{display:block;fill:#6b7c93;stroke:#6b7c93}.list-icon.svelte-1k1cmht.svelte-1k1cmht{grid-row:1/3;align-self:center;margin:8px}.in-map.svelte-1k1cmht.svelte-1k1cmht{height:30px}.maplibregl-canvas-container .marker-selected{z-index:1}.maplibregl-canvas-container svg.svelte-1k1cmht path.svelte-1k1cmht,.leaflet-map-pane svg.svelte-1k1cmht path.svelte-1k1cmht{fill:#3170fe;stroke:#3170fe}.marker-selected svg.svelte-1k1cmht path.svelte-1k1cmht{fill:#98b7ff;stroke:#3170fe}.marker-reverse svg.svelte-1k1cmht path.svelte-1k1cmht{fill:silver;stroke:gray}.marker-interactive{cursor:pointer!important}.marker-fuzzy svg.svelte-1k1cmht path.svelte-1k1cmht{fill:silver;stroke:gray}.marker-fuzzy.marker-selected svg.svelte-1k1cmht path.svelte-1k1cmht{fill:#ddd;stroke:silver}.maptiler-gc-popup>.maplibregl-popup-content{padding:2px 8px}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.52",
4
4
  "type": "module",
5
5
  "author": {
6
6
  "name": "Martin Ždila",
@@ -26,11 +26,13 @@
26
26
  "exports": {
27
27
  "./leaflet": {
28
28
  "import": "./dist/leaflet.js",
29
- "require": "./dist/leaflet.umd.js"
29
+ "require": "./dist/leaflet.umd.js",
30
+ "types": "./dist/lib/LeafletGeocodingControl.d.ts"
30
31
  },
31
32
  "./maplibregl": {
32
33
  "import": "./dist/maplibregl.js",
33
- "require": "./dist/maplibregl.umd.js"
34
+ "require": "./dist/maplibregl.umd.js",
35
+ "types": "./dist/lib/MaplibreglGeocodingControl.d.ts"
34
36
  },
35
37
  "./dist/style.css": {
36
38
  "import": "./dist/style.css",
@@ -43,24 +45,24 @@
43
45
  },
44
46
  "types": "./dist/lib/index.d.ts",
45
47
  "devDependencies": {
46
- "@sveltejs/vite-plugin-svelte": "^1.3.1",
48
+ "@sveltejs/vite-plugin-svelte": "^2.0.2",
47
49
  "@tsconfig/svelte": "^3.0.0",
48
50
  "@turf/buffer": "^6.5.0",
49
51
  "@turf/difference": "^6.5.0",
50
52
  "@turf/union": "^6.5.0",
51
53
  "@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",
54
+ "prettier": "^2.8.3",
55
+ "prettier-plugin-svelte": "^2.9.0",
56
+ "svelte": "^3.55.1",
57
+ "svelte-check": "^3.0.2",
58
+ "svelte-preprocess": "^5.0.0",
57
59
  "tslib": "^2.4.1",
58
- "typescript": "^4.9.3",
59
- "vite": "^3.2.4"
60
+ "typescript": "^4.9.4",
61
+ "vite": "^4.0.4"
60
62
  },
61
63
  "peerDependencies": {
62
- "leaflet": "^1.9.2",
63
- "maplibre-gl": "> 1.14.0"
64
+ "leaflet": "^1.9.3",
65
+ "maplibre-gl": "^2.4.0"
64
66
  },
65
67
  "peerDependenciesMeta": {
66
68
  "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 country: 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,18 @@
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 (country) {
329
+ sp.set("country", Array.isArray(country) ? country.join(",") : country);
330
+ }
331
+
332
+ if (types) {
333
+ sp.set("types", types.join(","));
277
334
  }
278
335
 
279
336
  if (!isReverse) {
@@ -285,12 +342,16 @@
285
342
  sp.set("proximity", proximity.map((c) => c.toFixed(6)).join(","));
286
343
  }
287
344
 
288
- // sp.set("autocomplete", String(autocomplete));
345
+ if (exact || !showResultsWhileTyping) {
346
+ sp.set("autocomplete", "false");
347
+ }
289
348
 
290
- // sp.set("fuzzyMatch", String(fuzzy));
349
+ sp.set("fuzzyMatch", String(fuzzyMatch));
291
350
  }
292
351
 
293
- // sp.set("limit", String(limit));
352
+ if (limit !== undefined) {
353
+ sp.set("limit", String(limit));
354
+ }
294
355
 
295
356
  sp.set("key", apiKey);
296
357
 
@@ -365,11 +426,15 @@
365
426
 
366
427
  const bbox: [number, number, number, number] = [180, 90, -180, -90];
367
428
 
429
+ const fuzzyOnly = !markedFeatures.some((feature) => !feature.matching_text);
430
+
368
431
  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]);
432
+ if (fuzzyOnly || !feature.matching_text) {
433
+ bbox[0] = Math.min(bbox[0], feature.bbox?.[0] ?? feature.center[0]);
434
+ bbox[1] = Math.min(bbox[1], feature.bbox?.[1] ?? feature.center[1]);
435
+ bbox[2] = Math.max(bbox[2], feature.bbox?.[2] ?? feature.center[0]);
436
+ bbox[3] = Math.max(bbox[3], feature.bbox?.[3] ?? feature.center[1]);
437
+ }
373
438
  }
374
439
 
375
440
  if (mapController && markedFeatures.length > 0) {
@@ -382,11 +447,7 @@
382
447
  }
383
448
 
384
449
  // taken from Leaflet
385
- export function wrapNum(
386
- x: number,
387
- range: [number, number],
388
- includeMax: boolean
389
- ) {
450
+ function wrapNum(x: number, range: [number, number], includeMax: boolean) {
390
451
  const max = range[1],
391
452
  min = range[0],
392
453
  d = max - min;
@@ -447,6 +508,14 @@
447
508
  error = undefined;
448
509
  }
449
510
  }
511
+
512
+ function pick(feature: Feature) {
513
+ console.log(feature);
514
+
515
+ picked = feature;
516
+ searchValue = feature.place_name;
517
+ selectedItemIndex = -1;
518
+ }
450
519
  </script>
451
520
 
452
521
  <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
@@ -504,10 +573,10 @@
504
573
  <slot />
505
574
  </div>
506
575
 
507
- {#if !focusedDelayed}
508
- {""}
509
- {:else if error}
576
+ {#if error}
510
577
  <div class="error">{errorMessage}</div>
578
+ {:else if !focusedDelayed}
579
+ {""}
511
580
  {:else if listFeatures?.length === 0}
512
581
  <div class="no-results">{noResultsMessage}</div>
513
582
  {:else if focusedDelayed && listFeatures?.length}
@@ -519,11 +588,7 @@
519
588
  data-selected={selectedItemIndex === i}
520
589
  class:selected={selectedItemIndex === i}
521
590
  on:mouseover={() => (selectedItemIndex = i)}
522
- on:focus={() => {
523
- picked = feature;
524
- searchValue = feature.place_name.replace(/,.*/, "");
525
- selectedItemIndex = -1;
526
- }}
591
+ on:focus={() => pick(feature)}
527
592
  >
528
593
  <MarkerIcon displayIn="list" />
529
594
  <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,27 @@
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
+ }
70
+
71
+ :global(.maptiler-gc-popup > .maplibregl-popup-content) {
72
+ padding: 2px 8px;
73
+ }
63
74
  </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,57 @@ 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
+ iconSize: [25, 30],
87
+ tooltipAnchor: [1, -24],
88
+ }),
89
+ });
90
+ }
91
+
77
92
  const ctrl: MapController = {
78
- setProximityChangeHandler(
79
- _proximityChangeHandler: ((proximity: Proximity) => void) | undefined
80
- ): void {
81
- if (_proximityChangeHandler) {
82
- proximityChangeHandler = _proximityChangeHandler;
93
+ setEventHandler(handler: undefined | ((e: MapEvent) => void)): void {
94
+ if (handler) {
95
+ eventHandler = handler;
83
96
 
84
97
  map.on("moveend", handleMoveEnd);
85
98
 
86
99
  handleMoveEnd();
100
+
101
+ map.on("click", handleMapClick);
87
102
  } else {
88
103
  map.off("moveend", handleMoveEnd);
89
104
 
90
- proximityChangeHandler?.(undefined);
105
+ eventHandler?.({ type: "proximityChange", proximity: undefined });
91
106
 
92
- proximityChangeHandler = undefined;
93
- }
94
- },
107
+ eventHandler = undefined;
95
108
 
96
- setMapClickHandler(
97
- _mapClickHandler: ((coordinates: [number, number]) => void) | undefined
98
- ): void {
99
- mapClickHandler = _mapClickHandler;
100
-
101
- if (mapClickHandler) {
102
- map.on("click", handleMapClick);
103
- } else {
104
109
  map.off("click", handleMapClick);
105
110
  }
106
111
  },
107
112
 
108
113
  flyTo(center: [number, number], zoom: number) {
109
- map.flyTo(center, zoom, { duration: 2, ...flyToOptions });
114
+ map.flyTo([center[1], center[0]], zoom, { duration: 2, ...flyToOptions });
110
115
  },
111
116
 
112
117
  fitBounds(bbox: [number, number, number, number], padding: number): void {
@@ -123,10 +128,41 @@ export function createLeafletMapController(
123
128
  map.getContainer().style.cursor = reverse ? "crosshair" : "";
124
129
  },
125
130
 
131
+ setReverseMarker(coordinates: [number, number]) {
132
+ if (!marker) {
133
+ return;
134
+ }
135
+
136
+ const latLng =
137
+ coordinates && ([coordinates[1], coordinates[0]] as [number, number]);
138
+
139
+ if (reverseMarker) {
140
+ if (!latLng) {
141
+ reverseMarker.remove();
142
+
143
+ reverseMarker = undefined;
144
+ } else {
145
+ reverseMarker.setLatLng(latLng);
146
+ }
147
+ } else if (latLng) {
148
+ reverseMarker = (
149
+ typeof marker === "object"
150
+ ? new L.Marker(latLng, marker)
151
+ : createMarker(latLng)
152
+ ).addTo(map);
153
+
154
+ reverseMarker.getElement()?.classList.add("marker-reverse");
155
+ }
156
+ },
157
+
126
158
  setMarkers(
127
159
  markedFeatures: Feature[] | undefined,
128
160
  picked: Feature | undefined
129
161
  ): void {
162
+ if (!marker) {
163
+ return;
164
+ }
165
+
130
166
  function setData(data?: GeoJSON.GeoJSON) {
131
167
  resultLayer.clearLayers();
132
168
 
@@ -143,16 +179,6 @@ export function createLeafletMapController(
143
179
 
144
180
  setData();
145
181
 
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
182
  if (picked) {
157
183
  let handled = false;
158
184
 
@@ -218,19 +244,50 @@ export function createLeafletMapController(
218
244
  );
219
245
  }
220
246
 
221
- for (const feature of markedFeatures ?? []) {
222
- if (feature === picked) {
223
- continue;
224
- }
247
+ if (showResultMarkers) {
248
+ for (const feature of markedFeatures ?? []) {
249
+ if (feature === picked) {
250
+ continue;
251
+ }
225
252
 
226
- const pos: L.LatLngExpression = [feature.center[1], feature.center[0]];
253
+ const pos: L.LatLngExpression = [
254
+ feature.center[1],
255
+ feature.center[0],
256
+ ];
227
257
 
228
- markers.push(
229
- (typeof showResultMarkers === "object"
230
- ? new L.Marker(pos, showResultMarkers)
231
- : createMarker(pos)
232
- ).addTo(map)
233
- );
258
+ const marker =
259
+ typeof showResultMarkers === "object"
260
+ ? new L.Marker(pos, showResultMarkers)
261
+ : createMarker(pos, true);
262
+
263
+ marker
264
+ .addTo(map)
265
+ .bindTooltip(feature.place_name.replace(/,.*/, ""), {
266
+ direction: "top",
267
+ });
268
+
269
+ const element = marker.getElement();
270
+
271
+ if (element) {
272
+ element.addEventListener("click", (e) => {
273
+ e.stopPropagation();
274
+
275
+ eventHandler?.({ type: "markerClick", id: feature.id });
276
+ });
277
+
278
+ element.addEventListener("mouseenter", () => {
279
+ eventHandler?.({ type: "markerMouseEnter", id: feature.id });
280
+ });
281
+
282
+ element.addEventListener("mouseleave", () => {
283
+ eventHandler?.({ type: "markerMouseLeave", id: feature.id });
284
+ });
285
+
286
+ element.classList.toggle("marker-fuzzy", !!feature.matching_text);
287
+ }
288
+
289
+ markers.push(marker);
290
+ }
234
291
  }
235
292
  },
236
293