From f024e210cde6fb576317099e5d158ccb9f4c4c59 Mon Sep 17 00:00:00 2001 From: Max Kohler Date: Tue, 16 Jun 2026 17:45:23 +0200 Subject: [PATCH 1/6] Block out feature --- components/src/index.js | 1 + components/src/maplibre/Geocoder/Geocoder.mdx | 10 + .../maplibre/Geocoder/Geocoder.stories.svelte | 43 ++++ .../src/maplibre/Geocoder/Geocoder.svelte | 223 ++++++++++++++++++ .../src/maplibre/Geocoder/GeocoderAPIs.ts | 62 +++++ .../src/maplibre/Geocoder/GeocoderProps.ts | 37 +++ components/src/maplibre/Geocoder/index.js | 2 + .../GeocoderControl/GeocoderControl.mdx | 4 +- .../GeocoderControl.stories.svelte | 1 - .../src/maplibre/Map/Map.stories.svelte | 3 +- .../src/maplibre/MapControl/MapControl.svelte | 4 +- 11 files changed, 385 insertions(+), 5 deletions(-) create mode 100644 components/src/maplibre/Geocoder/Geocoder.mdx create mode 100644 components/src/maplibre/Geocoder/Geocoder.stories.svelte create mode 100644 components/src/maplibre/Geocoder/Geocoder.svelte create mode 100644 components/src/maplibre/Geocoder/GeocoderAPIs.ts create mode 100644 components/src/maplibre/Geocoder/GeocoderProps.ts create mode 100644 components/src/maplibre/Geocoder/index.js diff --git a/components/src/index.js b/components/src/index.js index 06dd7691..a3e4ba1d 100644 --- a/components/src/index.js +++ b/components/src/index.js @@ -29,6 +29,7 @@ export { default as Map } from './maplibre/Map/Map.svelte'; export { SWRDataLabLight, SWRDataLabDark } from './maplibre/MapStyle'; export { default as MapControl } from './maplibre/MapControl/MapControl.svelte'; export { default as AttributionControl } from './maplibre/AttributionControl/AttributionControl.svelte'; +export { default as Geocoder } from './maplibre/Geocoder/Geocoder.svelte'; export { default as GeocoderControl } from './maplibre/GeocoderControl/GeocoderControl.svelte'; export { default as NavigationControl } from './maplibre/NavigationControl/NavigationControl.svelte'; export { default as ScaleControl } from './maplibre/ScaleControl/ScaleControl.svelte'; diff --git a/components/src/maplibre/Geocoder/Geocoder.mdx b/components/src/maplibre/Geocoder/Geocoder.mdx new file mode 100644 index 00000000..29f5e713 --- /dev/null +++ b/components/src/maplibre/Geocoder/Geocoder.mdx @@ -0,0 +1,10 @@ +import { Story, Meta, Primary, Controls, Stories } from '@storybook/addon-docs/blocks'; + +import * as GeocoderStories from './Geocoder.stories.svelte'; + + + +# Geocoder + + + diff --git a/components/src/maplibre/Geocoder/Geocoder.stories.svelte b/components/src/maplibre/Geocoder/Geocoder.stories.svelte new file mode 100644 index 00000000..994de852 --- /dev/null +++ b/components/src/maplibre/Geocoder/Geocoder.stories.svelte @@ -0,0 +1,43 @@ + + + { + }} +> + + +
+ + +
+
+
+ + diff --git a/components/src/maplibre/Geocoder/Geocoder.svelte b/components/src/maplibre/Geocoder/Geocoder.svelte new file mode 100644 index 00000000..7644c1c0 --- /dev/null +++ b/components/src/maplibre/Geocoder/Geocoder.svelte @@ -0,0 +1,223 @@ + + +
+ + diff --git a/components/src/maplibre/Geocoder/GeocoderAPIs.ts b/components/src/maplibre/Geocoder/GeocoderAPIs.ts new file mode 100644 index 00000000..5cd82931 --- /dev/null +++ b/components/src/maplibre/Geocoder/GeocoderAPIs.ts @@ -0,0 +1,62 @@ +import { + type CarmenGeojsonFeature, + type MaplibreGeocoderApi, + type MaplibreGeocoderApiConfig, + type MaplibreGeocoderFeatureResults +} from '@maplibre/maplibre-gl-geocoder'; + +export class MaptilerGeocoderAPI implements MaplibreGeocoderApi { + key: string; + + constructor(key: string) { + this.key = key; + } + + async forwardGeocode(config: MaplibreGeocoderApiConfig): Promise { + const result: MaplibreGeocoderFeatureResults = { + type: 'FeatureCollection', + features: [] + }; + try { + const params = new URLSearchParams( + Object.fromEntries( + Object.entries({ + country: config.countries || '', + language: config.language || '', + types: config.types || '', + key: this.key || '' + }).filter(([_, value]) => { + return value !== ''; + }) + ) + ); + + const response = await fetch( + `https://api.maptiler.com/geocoding/${config.query}.json?${params.toString()}` + ); + const geojson = await response.json(); + for (const feature of geojson.features) { + const res: CarmenGeojsonFeature = { + type: 'Feature', + id: feature.id, + place_type: ['place'], + place_name: feature.place_name, + language: feature.properties.display_name, + text: feature.text, + bbox: feature.bbox, + geometry: { + type: 'Point', + coordinates: feature.center + }, + properties: { + text: feature.text + } + }; + result.features.push(res); + } + } catch (e) { + console.error(`Failed to forwardGeocode with error: ${e}`); + } + return result; + } +} diff --git a/components/src/maplibre/Geocoder/GeocoderProps.ts b/components/src/maplibre/Geocoder/GeocoderProps.ts new file mode 100644 index 00000000..86dbe744 --- /dev/null +++ b/components/src/maplibre/Geocoder/GeocoderProps.ts @@ -0,0 +1,37 @@ +import { Map } from "maplibre-gl"; +import { + type GeocodingCountry, + type GeocodingLanguage, + type GeocodingPlaceType, + type GeocodingService + } from '../types'; + + +export default interface GeocoderProps { + map: Map + service: GeocodingService; + /** + * API key for selected geocoding `service` + */ + key: string; + /** + * Limit the number of returned suggestions + */ + limit?: number; + /** + * Limit search to one or more countries + */ + countries?: GeocodingCountry | GeocodingCountry[]; + /** + * Limit search to one or more result type. + */ + types?: GeocodingPlaceType | GeocodingPlaceType[]; + /** + * Limit search to one or more languages. The UI is localised to the first language specified if [available](https://github.com/maplibre/maplibre-gl-geocoder/blob/main/lib/localization.ts). + */ + languages?: GeocodingLanguage | GeocodingLanguage[]; + /** + * Overwrite the default input placeholder + */ + placeholder?: string; + } diff --git a/components/src/maplibre/Geocoder/index.js b/components/src/maplibre/Geocoder/index.js new file mode 100644 index 00000000..ef694f5f --- /dev/null +++ b/components/src/maplibre/Geocoder/index.js @@ -0,0 +1,2 @@ +import Geocoder from './Geocoder.svelte'; +export default Geocoder; diff --git a/components/src/maplibre/GeocoderControl/GeocoderControl.mdx b/components/src/maplibre/GeocoderControl/GeocoderControl.mdx index b4d13201..d0a141a3 100644 --- a/components/src/maplibre/GeocoderControl/GeocoderControl.mdx +++ b/components/src/maplibre/GeocoderControl/GeocoderControl.mdx @@ -14,10 +14,10 @@ import * as GeocoderControlStories from './GeocoderControl.stories.svelte'; Maptiler doesn't allow filtering by German admin boundaries, but its `types` seem to map as follows: - + - + diff --git a/components/src/maplibre/GeocoderControl/GeocoderControl.stories.svelte b/components/src/maplibre/GeocoderControl/GeocoderControl.stories.svelte index 31c2f53f..36862a7c 100644 --- a/components/src/maplibre/GeocoderControl/GeocoderControl.stories.svelte +++ b/components/src/maplibre/GeocoderControl/GeocoderControl.stories.svelte @@ -35,7 +35,6 @@
{ - map?.removeControl(control); + if (control){ + map?.removeControl(control); + } }; }); From aef13eece3bd4171c328b58f70a2366cb648181e Mon Sep 17 00:00:00 2001 From: Max Kohler Date: Tue, 16 Jun 2026 17:57:19 +0200 Subject: [PATCH 2/6] refactor --- .../maplibre/Geocoder/Geocoder.stories.svelte | 28 ++- .../src/maplibre/Geocoder/Geocoder.svelte | 169 +-------------- .../src/maplibre/Geocoder/GeocoderProps.ts | 2 +- .../src/maplibre/Geocoder/geocoder.scss | 158 ++++++++++++++ .../GeocoderControl/GeocoderControl.mdx | 2 + .../GeocoderControl/GeocoderControl.svelte | 193 +----------------- 6 files changed, 185 insertions(+), 367 deletions(-) create mode 100644 components/src/maplibre/Geocoder/geocoder.scss diff --git a/components/src/maplibre/Geocoder/Geocoder.stories.svelte b/components/src/maplibre/Geocoder/Geocoder.stories.svelte index 994de852..54d9b6d9 100644 --- a/components/src/maplibre/Geocoder/Geocoder.stories.svelte +++ b/components/src/maplibre/Geocoder/Geocoder.stories.svelte @@ -6,13 +6,14 @@ import DesignTokens from '../../DesignTokens/DesignTokens.svelte'; import { SWRDataLabLight } from '../MapStyle'; import Map from '../Map/Map.svelte'; + import type { MapContext } from '../context.svelte'; const { Story } = defineMeta({ title: 'Maplibre/Extras/Geocoder', component: Geocoder }); - let mapContext = $state() + let mapContext: MapContext | undefined = $state(undefined) +
-
- - + languages="de" + service="maptiler" + key="V32kPHZjMa0Mkn6YvSzA" + map={mapContext?.map} + /> +
+
+
diff --git a/components/src/maplibre/Geocoder/Geocoder.svelte b/components/src/maplibre/Geocoder/Geocoder.svelte index 7644c1c0..7e3aac5a 100644 --- a/components/src/maplibre/Geocoder/Geocoder.svelte +++ b/components/src/maplibre/Geocoder/Geocoder.svelte @@ -1,13 +1,7 @@
type boundary
countyKreis
municipalityGemeinde
regionBundesland