diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..14524e7 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = LF +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = true +max_line_length = 180 diff --git a/.gitignore b/.gitignore index e48ed1d..6865660 100644 --- a/.gitignore +++ b/.gitignore @@ -7,11 +7,29 @@ yarn-error.log* pnpm-debug.log* lerna-debug.log* -node_modules -dist -dist.svelte -*.local -.svelte-kit +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Dependency directories +node_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity # Editor directories and files .vscode/* @@ -24,5 +42,4 @@ dist.svelte *.sln *.sw? -*.tgz -src/info.json +dist diff --git a/.lintstagedrc.json b/.lintstagedrc.json index 725c245..147f672 100644 --- a/.lintstagedrc.json +++ b/.lintstagedrc.json @@ -1,4 +1,4 @@ { "*": ["prettier --check"], - "*.{ts,svelte}": ["eslint"] + "*.{ts}": ["eslint"] } diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..2bdf114 --- /dev/null +++ b/.npmignore @@ -0,0 +1,12 @@ +images +demos +public +src +!dist/src +*.tgz +.github +.husky +.vscode +vite* +.* +tsconfig.json diff --git a/.prettierrc b/.prettierrc index 41ce08c..0824baa 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,4 @@ { - "plugins": ["prettier-plugin-svelte", "prettier-plugin-organize-imports"], - "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }], + "plugins": ["prettier-plugin-organize-imports"], "organizeImportsSkipDestructiveCodeActions": true } diff --git a/.vscode/extensions.json b/.vscode/extensions.json index bdef820..ecdeeee 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,3 +1,3 @@ { - "recommendations": ["svelte.svelte-vscode"] + "recommendations": ["runem.lit-plugin"] } diff --git a/README.md b/README.md index 3ca462e..6b71fb7 100644 --- a/README.md +++ b/README.md @@ -22,15 +22,15 @@ The _MapTiler Geocoding control_ implements a powerful search box in your maps or online forms, enabling your application users to find any place on Earth down to individual addresses. Use the search box control with [MapTiler SDK JS](https://docs.maptiler.com/sdk-js/) (or other map libraries like [Leaflet](https://docs.maptiler.com/leaflet/), [MapLibre GL JS](https://github.com/maplibre/maplibre-gl-js), [OpenLayers](https://docs.maptiler.com/openlayers/)). +> ⚠️ _MapTiler Geocoding control_ v3 support for _Leaflet_ (v1 and v2) and _OpenLayers_ is to be added soon. In the meantime, please use _MapTiler Geocoding control_ v2 with these map libraries. + ## Why? The _Geocoding control_ uses the [MapTiler Geocoding API](https://www.maptiler.com/cloud/geocoding/). You can use the API directly from your web or backend applications or use the [API Client JS](https://docs.maptiler.com/client-js/) library. -With this control, users of -mapping application can: +With this control, users of mapping application can: -- Find any place on Earth (States, Cities, Streets, Addresses, POIs, ...) down - to the address level +- Find any place on Earth (States, Cities, Streets, Addresses, POIs, ...) down to the address level - Find and identify objects or place names using a coordinate pair or a single mouse click (reverse geocoding) - Restrict the search area to a specific country, bounding box, or proximity - Highlight searched results on the map (marker or full geometry) @@ -39,17 +39,11 @@ mapping application can: The component can be used as an ES module or UMD module with or without bundler. -Geocoding control is also provided as [React component](https://docs.maptiler.com/sdk-js/modules/geocoding/api/usage/react/) and [Svelte component](https://docs.maptiler.com/sdk-js/modules/geocoding/api/usage/svelte/) and [other libraries](#installation-and-more-usage-examples). +Geocoding control itself is provided as a [Web component](https://developer.mozilla.org/en-US/docs/Web/API/Web_components) which can be used with [React](https://docs.maptiler.com/sdk-js/modules/geocoding/api/usage/react/), [Svelte](https://docs.maptiler.com/sdk-js/modules/geocoding/api/usage/svelte/), and any other modern frontend library, or without any library at all. ## Install -Install the Geocoding control unsing `npm`: - -**⚠️ Warning! ⚠️** - -The current version of Geocoding Control is only compatible with Svelte v4, this will potentially cause peer dependency issues when installing with certain versions of npm in Svelte projects (eg if you're using Svelte v5), or if you intend to import the Svelte component directly. - -If you are using a this library in a Svelte project you can npm install with `--force` or `--legacy-peer-deps` and use only the **pre-compiled `GeoLocatControl` vanilla module**, not the Svelte component. +Install the Geocoding control unsing `npm`, together with your map library (MapTiler SDK as an example): ```shell npm install --save @maptiler/geocoding-control @maptiler/sdk @@ -57,7 +51,7 @@ npm install --save @maptiler/geocoding-control @maptiler/sdk ## Quick start -Use the component in your mapping application: +Use the component in your mapping application (MapTiler SDK as an example): ```js import * as maptilersdk from "@maptiler/sdk"; @@ -80,21 +74,22 @@ NOTE: Get your personal [MapTiler API key](https://docs.maptiler.com/cloud/api/a ## Installation and more usage examples -- [With MapTiler SDK](https://docs.maptiler.com/sdk-js/modules/geocoding/api/usage/sdk-js/) -- [With MapLibre GL](https://docs.maptiler.com/sdk-js/modules/geocoding/api/usage/maplibre-gl-js/) -- [With Leaflet](https://docs.maptiler.com/sdk-js/modules/geocoding/api/usage/leaflet/) -- [With OpenLayers](https://docs.maptiler.com/sdk-js/modules/geocoding/api/usage/openlayers/) -- [As a React component](https://docs.maptiler.com/sdk-js/modules/geocoding/api/usage/react/) -- [As Svelte component](https://docs.maptiler.com/sdk-js/modules/geocoding/api/usage/svelte/) -- [As vanilla JavaScript module](https://docs.maptiler.com/sdk-js/modules/geocoding/api/usage/vanilla-js/) +- [As a standalone Geocoding component](https://docs.maptiler.com/sdk-js/modules/geocoding/api/usage/standalone/) _(to be updated for v3)_ +- [With MapTiler SDK](https://docs.maptiler.com/sdk-js/modules/geocoding/api/usage/sdk-js/) _(to be updated for v3)_ +- [With MapLibre GL](https://docs.maptiler.com/sdk-js/modules/geocoding/api/usage/maplibre-gl-js/) _(to be updated for v3)_ +- [With Leaflet](https://docs.maptiler.com/sdk-js/modules/geocoding/api/usage/leaflet/) _(to be updated for v3)_ +- [With OpenLayers](https://docs.maptiler.com/sdk-js/modules/geocoding/api/usage/openlayers/) _(to be updated for v3)_ +- [As a React component](https://docs.maptiler.com/sdk-js/modules/geocoding/api/usage/react/) _(to be updated for v3)_ +- [As Svelte component](https://docs.maptiler.com/sdk-js/modules/geocoding/api/usage/svelte/) _(to be updated for v3)_ +- [As vanilla JavaScript module](https://docs.maptiler.com/sdk-js/modules/geocoding/api/usage/vanilla-js/) _(to be updated for v3)_ ## API Documentation In addition to the details and examples provided in this `README.md` and our documentation, check out - [The complete Geocoding service API documentation](https://docs.maptiler.com/cloud/api/geocoding/) -- [The complete Geocoding control reference](https://docs.maptiler.com/sdk-js/modules/geocoding/api/api-reference/) -- [UMD global variables](https://docs.maptiler.com/sdk-js/modules/geocoding/#umd-global-variables) +- [The complete Geocoding control reference](https://docs.maptiler.com/sdk-js/modules/geocoding/api/api-reference/) _(to be updated for v3)_ +- [UMD global variables](https://docs.maptiler.com/sdk-js/modules/geocoding/#umd-global-variables) _(to be updated for v3)_ ## Development @@ -112,6 +107,8 @@ You will find compilation result in the `dist` directory. npm install && VITE_API_KEY=YOUR_MAPTILER_API_KEY_HERE npm run dev ``` +Alternatively, you can provide your API key via `key` URL param. + ### POI icons and bundlers POI icons are served from CDN per default. If there is an requirement to serve them from a different location and the control is used in the application which is built with Web Application bundler (like Webpack or Vite) then it is necessary to do some extra configuration. Icons are bundled in the library and you can find them in `node_modules/@maptiler/geocoding-control/icons`. Configure your bundler and/or provide `iconsBaseUrl` option for the icons to be properly resolved. You can also copy icons from that directory to your `public` directory. diff --git a/SECURITY.md b/SECURITY.md index 843973d..8236527 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,9 +4,12 @@ Following versions are supported with security updateds: -| Version | Supported | -| ------- | ------------------ | -| 0.0.x | :white_check_mark: | +| Version | Supported | +| ------- | --------- | +| 0.0.x | ❌ | +| 1.x.x | ❌ | +| 2.x.x | ❌ | +| 3.x.x | ✅ | ## Reporting a Vulnerability diff --git a/create-cdn-pr.sh b/create-cdn-pr.sh deleted file mode 100755 index 8923268..0000000 --- a/create-cdn-pr.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -set -e - -export GIT_WORK_TREE=../cdn.maptiler.com -export GIT_DIR=$GIT_WORK_TREE/.git - -git checkout main - -git pull - -VERSION=$npm_package_version - -git checkout -b maptiler-geocoding-control-$VERSION - -BASE=../cdn.maptiler.com/maptiler-geocoding-control - -mkdir -p $BASE/v$VERSION - -cp -r dist/* $BASE/v$VERSION - -ln -sfn v$VERSION $BASE/latest - -git add maptiler-geocoding-control/v$VERSION maptiler-geocoding-control/latest - -git reset maptiler-geocoding-control/v$VERSION/*.tgz - -git commit -m "Add maptiler-geocoding-control v$VERSION" - -gh pr create --base main --fill --repo maptiler/cdn.maptiler.com diff --git a/demos/.env b/demos/.env new file mode 100644 index 0000000..7df3ad2 --- /dev/null +++ b/demos/.env @@ -0,0 +1,2 @@ +VITE_API_URL=https://api.maptiler.com/geocoding +VITE_LIB_VERSION=$npm_package_version diff --git a/demos/01-standalone.html b/demos/01-standalone.html new file mode 100644 index 0000000..67fc9dc --- /dev/null +++ b/demos/01-standalone.html @@ -0,0 +1,18 @@ + + + MapTiler Geocoding Control example + + + + + + + + + diff --git a/demos/02-maptiler-sdk.html b/demos/02-maptiler-sdk.html new file mode 100644 index 0000000..8b62735 --- /dev/null +++ b/demos/02-maptiler-sdk.html @@ -0,0 +1,29 @@ + + + MapTiler Geocoding Control example + + + + +
+ + + diff --git a/demos/03-maplibregl.html b/demos/03-maplibregl.html new file mode 100644 index 0000000..8087653 --- /dev/null +++ b/demos/03-maplibregl.html @@ -0,0 +1,29 @@ + + + MapTiler Geocoding Control example + + + + +
+ + + diff --git a/demos/04-react.html b/demos/04-react.html new file mode 100644 index 0000000..1341824 --- /dev/null +++ b/demos/04-react.html @@ -0,0 +1,61 @@ + + + MapTiler Geocoding Control example + + + + + +
+ + + diff --git a/demos/eslint.config.js b/demos/eslint.config.js new file mode 100644 index 0000000..b7054d1 --- /dev/null +++ b/demos/eslint.config.js @@ -0,0 +1,11 @@ +// @ts-nocheck + +import tseslint from "typescript-eslint"; +import baseConfig from "../eslint.config.js"; + +export default tseslint.config(baseConfig, { + rules: { + "@typescript-eslint/no-unsafe-argument": "off", + "@typescript-eslint/no-unsafe-assignment": "off", + }, +}); diff --git a/demos/index.html b/demos/index.html new file mode 100644 index 0000000..f23f088 --- /dev/null +++ b/demos/index.html @@ -0,0 +1,57 @@ + + + + + + + MapTiler Geocoding Control Demos + + + + + +
+
+ + Standalone → + MapTiler SDK → + MapLibre GL → + React → +
+
+ + diff --git a/demos/public/maptiler-sdk-logo.svg b/demos/public/maptiler-sdk-logo.svg new file mode 100644 index 0000000..084223b --- /dev/null +++ b/demos/public/maptiler-sdk-logo.svg @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demos/src/01-standalone.ts b/demos/src/01-standalone.ts new file mode 100644 index 0000000..9e16837 --- /dev/null +++ b/demos/src/01-standalone.ts @@ -0,0 +1,7 @@ +import "../../src"; + +import { getApiKey } from "./demo-utils"; + +for (const el of document.querySelectorAll("maptiler-geocoder")) { + el.apiKey = getApiKey(); +} diff --git a/demos/src/02-maptiler-sdk.ts b/demos/src/02-maptiler-sdk.ts new file mode 100644 index 0000000..8b1860c --- /dev/null +++ b/demos/src/02-maptiler-sdk.ts @@ -0,0 +1,49 @@ +import { Map, MapStyle } from "@maptiler/sdk"; +import "@maptiler/sdk/dist/maptiler-sdk.css"; + +import { GeocodingControl } from "../../src/maptilersdk"; + +import { getApiKey } from "./demo-utils"; + +const map = new Map({ + container: "map", + apiKey: getApiKey(), + style: MapStyle.STREETS, + hash: true, + navigationControl: true, +}); + +const geocodingControl = new GeocodingControl({ + enableReverse: "button", + collapsed: true, + // pickedResultStyle: "full-geometry-including-polygon-center-marker", + // limit: 20, + // types: ["poi"], + // fetchParameters: { credentials: "include" }, + // selectFirst: false, + iconsBaseUrl: "/assets/icons/", + proximity: [ + { type: "map-center", minZoom: 12 }, + { type: "client-geolocation", minZoom: 8 }, + { type: "server-geolocation", minZoom: 8 }, + ], +}); + +map.addControl(geocodingControl); + +geocodingControl.on("featureslisted", (e) => { + console.log(e); +}); + +map.addControl( + new GeocodingControl({ + keepListOpen: true, + enableReverse: "button", + collapsed: false, + pickedResultStyle: "full-geometry", + types: ["locality"], + fullGeometryStyle: true, + iconsBaseUrl: "/assets/icons/", + }), + "top-left", +); diff --git a/demos/src/03-maplibregl.ts b/demos/src/03-maplibregl.ts new file mode 100644 index 0000000..1b28c39 --- /dev/null +++ b/demos/src/03-maplibregl.ts @@ -0,0 +1,86 @@ +import maplibregl from "maplibre-gl"; +import "maplibre-gl/dist/maplibre-gl.css"; + +import { GeocodingControl } from "../../src/maplibregl"; + +import { getApiKey } from "./demo-utils"; + +const map = new maplibregl.Map({ + container: "map", + style: `https://api.maptiler.com/maps/streets/style.json?key=${getApiKey()}`, + hash: true, +}); + +const geocodingControl = new GeocodingControl({ + apiKey: getApiKey(), + enableReverse: "button", + collapsed: true, + // limit: 20, + // types: ["poi"], + // fetchParameters: { credentials: "include" }, + // selectFirst: false, + iconsBaseUrl: "/assets/icons/", + proximity: [ + { type: "map-center", minZoom: 12 }, + { type: "client-geolocation", minZoom: 8 }, + { type: "server-geolocation", minZoom: 8 }, + ], + adjustUrl(url) { + // for reverse geocoding use only address type + if (/\/\d+\.?\d*%2C\d+.?\d*.json$/.test(url.pathname)) { + url.searchParams.set("types", "address"); + url.searchParams.set("limit", "5"); + } + }, + marker(map, feature) { + if (!feature) { + return; + } + + const marker = new maplibregl.Marker() + .setLngLat(feature.center) + .setPopup(new maplibregl.Popup({ closeButton: false }).setText(feature.text)) + .addTo(map) + .togglePopup(); + + const element = marker.getElement(); + + element.style.cursor = "pointer"; + + element.addEventListener("click", (e) => { + marker.togglePopup(); + e.stopPropagation(); + }); + + return marker; + }, + showResultMarkers(map, feature) { + return new maplibregl.Marker() + .setLngLat(feature.center) + .setPopup(new maplibregl.Popup({ closeButton: false }).setText(feature.text)) + .addTo(map) + .togglePopup(); + }, +}); + +map.addControl(geocodingControl); + +geocodingControl.on("featureslisted", (e) => { + console.log(e); +}); + +map.addControl(new maplibregl.NavigationControl()); + +map.addControl( + new GeocodingControl({ + apiKey: getApiKey(), + keepListOpen: true, + enableReverse: "button", + collapsed: false, + pickedResultStyle: "full-geometry", + types: ["locality"], + fullGeometryStyle: true, + iconsBaseUrl: "/assets/icons/", + }), + "top-left", +); diff --git a/examples/react/main.tsx b/demos/src/04-react.tsx similarity index 51% rename from examples/react/main.tsx rename to demos/src/04-react.tsx index 270a3bb..d22bdcd 100644 --- a/examples/react/main.tsx +++ b/demos/src/04-react.tsx @@ -1,10 +1,10 @@ -import * as maptilersdk from "@maptiler/sdk"; +import { MapStyle, Map as SDKMap, config } from "@maptiler/sdk"; import "@maptiler/sdk/dist/maptiler-sdk.css"; import { createElement, useEffect, useRef, useState } from "react"; import { createRoot } from "react-dom/client"; -import type { EnableReverse } from "src/types"; -import { createMapLibreGlMapController } from "../../src/maplibregl-controller"; -import { GeocodingControl, type Methods } from "../../src/react"; + +import { GeocodingControl, type EnableReverse } from "../../src/maptilersdk"; +import { getApiKey } from "./demo-utils"; const appElement = document.getElementById("app"); @@ -12,28 +12,16 @@ if (!appElement) { throw new Error("element with id 'app' not found"); } -const apiKey = import.meta.env.VITE_API_KEY; - -if (!apiKey) { - const errMsg = "missing VITE_API_KEY environment variable"; - - window.alert(errMsg); - - throw new Error(errMsg); -} - -maptilersdk.config.apiKey = apiKey; +config.apiKey = getApiKey(); const root = createRoot(appElement); function App() { - const ref = useRef(null); - const consoleRef = useRef(null); const [collapsed, setCollapsed] = useState(false); - const [reverse, setReverse] = useState("always"); + const [enableReverse, setEnableReverse] = useState("always"); const [clearOnBlur, setClearOnBlur] = useState(false); @@ -45,29 +33,90 @@ function App() { const [selectFirst, setSelectFirst] = useState(true); - const map = useRef(null); + const control = useRef(null); - const mapContainer = useRef(null); + const map = useRef(null); - const [mapController, setMapController] = useState | null>(null); + const mapContainer = useRef(null); useEffect(() => { - if (map.current || !mapContainer.current) { + if (map.current || control.current || !mapContainer.current) { return; } - map.current = new maptilersdk.Map({ + map.current = new SDKMap({ container: mapContainer.current, - style: maptilersdk.MapStyle.STREETS, + style: MapStyle.STREETS, center: [15, 49], zoom: 8, }); - setMapController(createMapLibreGlMapController(map.current, maptilersdk)); + control.current = new GeocodingControl({ + placeholder: "What would you like to find?", + clearButtonTitle: "Clear me!", + errorMessage: "Boo!", + noResultsMessage: "No such place found!", + // reverseGeocodingLimit: 5, + // reverseGeocodingTypes: ["address"], + iconsBaseUrl: "/assets/icons/", + }); + + control.current.on("select", (data) => { + log("select", data); + }); + control.current.on("pick", (data) => { + log("pick", data); + }); + control.current.on("featureslisted", (data) => { + log("featuresListed", data); + }); + control.current.on("featuresmarked", (data) => { + log("featuresMarked", data); + }); + control.current.on("optionsvisibilitychange", (data) => { + log("optionsVisibilityChange", data); + }); + control.current.on("querychange", (data) => { + log("queryChange", data); + }); + control.current.on("reversetoggle", (data) => { + log("reverseToggle", data); + }); + control.current.on("response", (data) => { + log("response", data); + }); + + map.current.addControl(control.current); }, []); + useEffect(() => { + control.current?.setOptions({ collapsed }); + }, [collapsed]); + + useEffect(() => { + control.current?.setOptions({ clearOnBlur }); + }, [clearOnBlur]); + + useEffect(() => { + control.current?.setOptions({ clearListOnPick }); + }, [clearListOnPick]); + + useEffect(() => { + control.current?.setOptions({ keepListOpen }); + }, [keepListOpen]); + + useEffect(() => { + control.current?.setOptions({ enableReverse }); + }, [enableReverse]); + + useEffect(() => { + control.current?.setOptions({ flyToSelected }); + }, [flyToSelected]); + + useEffect(() => { + control.current?.setOptions({ selectFirst }); + }, [selectFirst]); + function log(action: string, data: unknown) { const el = consoleRef.current; @@ -92,43 +141,13 @@ function App() { <>
- {mapController && ( - log("select", data)} - onPick={(data) => log("pick", data)} - onFeaturesListed={(data) => log("featuresListed", data)} - onFeaturesMarked={(data) => log("featuresMarked", data)} - onOptionsVisibilityChange={(data) => - log("optionsVisibilityChange", data) - } - onQueryChange={(data) => log("queryChange", data)} - onReverseToggle={(data) => log("reverseToggle", data)} - onResponse={(data) => log("response", data)} - clearOnBlur={clearOnBlur} - clearListOnPick={clearListOnPick} - keepListOpen={keepListOpen} - iconsBaseUrl="/icons/" - enableReverse={reverse} - flyToSelected={flyToSelected} - selectFirst={selectFirst} - // reverseGeocodingLimit={5} - // reverseGeocodingTypes={["address"]} - /> - )} - @@ -137,7 +156,9 @@ function App() { setClearOnBlur(e.currentTarget.checked)} + onChange={(e) => { + setClearOnBlur(e.currentTarget.checked); + }} /> Clear on blur @@ -146,7 +167,9 @@ function App() { setClearListOnPick(e.currentTarget.checked)} + onChange={(e) => { + setClearListOnPick(e.currentTarget.checked); + }} /> Clear list on pick @@ -155,7 +178,9 @@ function App() { setSelectFirst(e.currentTarget.checked)} + onChange={(e) => { + setSelectFirst(e.currentTarget.checked); + }} /> Select first @@ -164,7 +189,9 @@ function App() { setFlyToSelected(e.currentTarget.checked)} + onChange={(e) => { + setFlyToSelected(e.currentTarget.checked); + }} /> Fly to selected @@ -173,17 +200,19 @@ function App() { setKeepListOpen(e.currentTarget.checked)} + onChange={(e) => { + setKeepListOpen(e.currentTarget.checked); + }} /> Keep the list open - - -
diff --git a/demos/src/demo-utils.ts b/demos/src/demo-utils.ts new file mode 100644 index 0000000..ed6c3e8 --- /dev/null +++ b/demos/src/demo-utils.ts @@ -0,0 +1,22 @@ +/** + * Gets the MapTiler API key for the SDK. + * If you don't want to use the URL parameter, you can set the key directly in the code. + */ +export function getApiKey(): string { + const apiKey: string = import.meta.env.VITE_API_KEY ?? localStorage.getItem("MT_DEMO_API_KEY") ?? "API_KEY"; + + if (apiKey === "API_KEY") { + const urlParams = new URLSearchParams(window.location.search); + const apiKey = urlParams.get("key"); + if (apiKey) { + localStorage.setItem("MT_DEMO_API_KEY", apiKey); + return apiKey; + } else { + const errorMessage = "MapTiler API key is missing. Please use URL `key` parameter to set it (`?key=XXXXX`)."; + alert(errorMessage); + throw new Error(errorMessage); + } + } else { + return apiKey; + } +} diff --git a/demos/src/vite-env.d.ts b/demos/src/vite-env.d.ts new file mode 100644 index 0000000..cda6d74 --- /dev/null +++ b/demos/src/vite-env.d.ts @@ -0,0 +1,5 @@ +/// + +interface ImportMetaEnv { + VITE_API_KEY?: string; +} diff --git a/demos/tsconfig.json b/demos/tsconfig.json new file mode 100644 index 0000000..3b19257 --- /dev/null +++ b/demos/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../tsconfig.json", + "baseUrl": ".", + "compilerOptions": { + "noUnusedLocals": false, + "noUnusedParameters": false, + "moduleResolution": "node", + "resolveJsonModule": true + } +} diff --git a/deno.lock b/deno.lock deleted file mode 100644 index 7056642..0000000 --- a/deno.lock +++ /dev/null @@ -1,56 +0,0 @@ -{ - "version": "4", - "redirects": { - "https://cdn.skypack.dev/chroma-js": "https://cdn.skypack.dev/new/chroma-js@v3.1.2/dist=es2019", - "https://cdn.skypack.dev/new/chroma-js@v3.1.2/dist=es2019": "https://cdn.skypack.dev/error/build:chroma-js@v3.1.2-QwkMr4VCpNO0CLkbGUyZ" - }, - "remote": { - "https://cdn.skypack.dev/error/build:chroma-js@v3.1.2-QwkMr4VCpNO0CLkbGUyZ": "97aee30af87a5f6905a6af1a3eb1ed523426de337cf7d92ed3604a6b289eca8b" - }, - "workspace": { - "packageJson": { - "dependencies": [ - "npm:@maptiler/sdk@^2.5.0", - "npm:@sveltejs/package@^2.3.7", - "npm:@sveltejs/vite-plugin-svelte@^3.1.2", - "npm:@tsconfig/svelte@^5.0.4", - "npm:@turf/bbox@^7.1.0", - "npm:@turf/clone@^7.1.0", - "npm:@turf/difference@^7.1.0", - "npm:@turf/flatten@^7.1.0", - "npm:@turf/union@^7.1.0", - "npm:@types/geojson@^7946.0.15", - "npm:@types/leaflet@^1.9.15", - "npm:@types/node@^22.10.1", - "npm:@types/react-dom@^19.0.2", - "npm:@types/react@^19.0.1", - "npm:concurrently@^9.1.0", - "npm:dotenv@^16.4.7", - "npm:eslint-plugin-svelte@^2.46.1", - "npm:eslint@^9.16.0", - "npm:esm-env@^1.2.1", - "npm:geo-coordinates-parser@^1.7.4", - "npm:globals@^15.13.0", - "npm:husky@^9.1.7", - "npm:leaflet@^1.9.4", - "npm:lint-staged@^15.2.11", - "npm:maplibre-gl@^4.7.1", - "npm:ol@10.3", - "npm:prettier-plugin-organize-imports@^4.1.0", - "npm:prettier-plugin-svelte@^3.3.2", - "npm:prettier@^3.4.2", - "npm:react-dom@19", - "npm:react@19", - "npm:replace-in-file@^8.2.0", - "npm:sass@^1.82.0", - "npm:svelte-check@^4.1.1", - "npm:svelte-preprocess@^6.0.3", - "npm:svelte@^4.2.19", - "npm:tslib@^2.8.1", - "npm:typescript-eslint@^8.18.0", - "npm:typescript@^5.7.2", - "npm:vite@^5.4.11" - ] - } - } -} diff --git a/eslint.config.js b/eslint.config.js index e63bd43..c9b71c6 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,61 +1,134 @@ -import js from "@eslint/js"; -import tsParser from "@typescript-eslint/parser"; -import eslintPluginSvelte from "eslint-plugin-svelte"; -import globals from "globals"; -import svelteParser from "svelte-eslint-parser"; -import tsEslint from "typescript-eslint"; +import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended"; +import { defineConfig, globalIgnores } from "eslint/config"; +import tseslint from "typescript-eslint"; -export default [ - js.configs.recommended, - ...tsEslint.configs.strict, - ...eslintPluginSvelte.configs["flat/recommended"], - ...eslintPluginSvelte.configs["flat/prettier"], +export default defineConfig( + globalIgnores(["dist/", "vite.config*.ts", "**/eslint.config.js"]), + // https://typescript-eslint.io/getting-started/typed-linting/ + tseslint.configs.strictTypeChecked, + tseslint.configs.stylisticTypeChecked, + tseslint.configs.recommendedTypeChecked, { + // forked from https://www.npmjs.com/package/eslint-plugin-restrict-imports + plugins: { + import: { + rules: { + "default-imports-only": { + meta: { + type: "suggestion", + docs: {}, + schema: [ + { + bannedImport: { + locations: ["filePaths"], + message: "string", + fixedLocation: "string", + }, + }, + ], + }, + create: function (context) { + const filePath = context.filename; + const options = context.options[0] ?? { + "^/(.*)": { + locations: ["(.*)"], + }, + }; + + return { + ImportDeclaration: (node) => { + Object.entries(options).forEach(([bannedImport, config]) => { + const importLocationRegex = new RegExp(bannedImport); + + if (config.ignoreTypeImports && node.importKind === "type") return; + + if (importLocationRegex.test(node.source.value)) { + config.locations.forEach((fp) => { + const bannedLocationRegex = new RegExp(fp); + + if (bannedLocationRegex.test(filePath)) { + node.specifiers.forEach((specifier) => { + if (specifier.type !== "ImportDefaultSpecifier") { + context.report({ + // @ts-expect-error `message` seems to work with this... + message: config.message ?? `Importing from '${bannedImport}' is banned in '${fp}'`, + node, + }); + } + }); + } + }); + } + }); + }, + }; + }, + }, + }, + }, + }, rules: { - "no-undef": "off", - "@typescript-eslint/no-unused-vars": [ - "error", - { ignoreRestSiblings: true }, - ], - // TODO for the reason of next 2 rules see https://github.com/eslint/eslint/issues/19134#issuecomment-2480588649 - "@typescript-eslint/no-unused-expressions": [ + "import/default-imports-only": [ "error", { - allowShortCircuit: true, - allowTernary: true, + "maplibre-gl$": { + locations: ["^(?!.*\.d\.ts$).*\.((ts|js))$"], + message: `Maplibre-gl uses CJS modules, only default imports are supported, named imports may fail on some setups.`, + ignoreTypeImports: true, + }, }, ], - "@typescript-eslint/no-empty-function": [ - "error", - { allow: ["arrowFunctions"] }, - ], }, }, { - ignores: [ - "dist/", - "dist.svelte/", - ".svelte-kit/", - "replace-env-vars.js", - "eslint.config.js", - "svelte.config.js", - ], - }, - { - files: ["**/*.svelte"], languageOptions: { - ecmaVersion: 2022, - sourceType: "module", - globals: { - ...globals.browser, - RequestInit: false, - }, - parser: svelteParser, parserOptions: { - parser: tsParser, - // project: true, - extraFileExtensions: [".svelte"], + projectService: true, + tsconfigRootDir: import.meta.dirname, + allowDefaultProject: [], }, }, }, -]; + // https://github.com/prettier/eslint-plugin-prettier + eslintPluginPrettierRecommended, + // + { + rules: { + "@typescript-eslint/array-type": "off", + "@typescript-eslint/consistent-indexed-object-style": "warn", + "@typescript-eslint/consistent-type-definitions": "off", + "@typescript-eslint/no-base-to-string": "warn", + "@typescript-eslint/no-confusing-void-expression": "warn", + "@typescript-eslint/no-explicit-any": "warn", + "@typescript-eslint/no-empty-function": "warn", // this is to satisfy maplibre-gl custom layer interface + "@typescript-eslint/no-floating-promises": "warn", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-misused-promises": "warn", + "@typescript-eslint/no-unnecessary-boolean-literal-compare": "off", + "@typescript-eslint/no-unnecessary-condition": "warn", + "@typescript-eslint/no-unnecessary-type-arguments": "off", + "@typescript-eslint/no-unnecessary-type-assertion": "off", + "@typescript-eslint/no-unnecessary-type-parameters": "off", + "@typescript-eslint/no-unused-vars": "warn", + "@typescript-eslint/no-unsafe-argument": "warn", + "@typescript-eslint/no-unsafe-assignment": "warn", + "@typescript-eslint/no-unsafe-call": "warn", + "@typescript-eslint/no-unsafe-enum-comparison": "off", + "@typescript-eslint/no-unsafe-member-access": "warn", + "@typescript-eslint/no-unsafe-return": "warn", + "@typescript-eslint/no-non-null-assertion": "warn", + "@typescript-eslint/non-nullable-type-assertion-style": "warn", + "@typescript-eslint/prefer-for-of": "off", + "@typescript-eslint/prefer-nullish-coalescing": "warn", + "@typescript-eslint/prefer-optional-chain": "off", + "@typescript-eslint/prefer-return-this-type": "off", + "@typescript-eslint/prefer-string-starts-ends-with": "warn", + "@typescript-eslint/restrict-plus-operands": "warn", + "@typescript-eslint/restrict-template-expressions": "warn", + "@typescript-eslint/related-getter-setter-pairs": "off", + "@typescript-eslint/unbound-method": "warn", + "@typescript-eslint/use-unknown-in-catch-callback-variable": "warn", + }, + }, + // +); diff --git a/examples/leaflet/AppLeaflet.svelte b/examples/leaflet/AppLeaflet.svelte deleted file mode 100644 index 3dbd1cd..0000000 --- a/examples/leaflet/AppLeaflet.svelte +++ /dev/null @@ -1,71 +0,0 @@ - - -
- - diff --git a/examples/leaflet/index.html b/examples/leaflet/index.html deleted file mode 100644 index dadbaa3..0000000 --- a/examples/leaflet/index.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - -MapTiler Geocoding Control :: Leaflet - -
- - diff --git a/examples/leaflet/main.ts b/examples/leaflet/main.ts deleted file mode 100644 index ab5f765..0000000 --- a/examples/leaflet/main.ts +++ /dev/null @@ -1,9 +0,0 @@ -import App from "./AppLeaflet.svelte"; - -const appElement = document.getElementById("app"); - -if (!appElement) { - throw new Error("element with id 'app' not found"); -} - -export default new App({ target: appElement }); diff --git a/examples/maplibregl/AppMapLibreGl.svelte b/examples/maplibregl/AppMapLibreGl.svelte deleted file mode 100644 index f331b4b..0000000 --- a/examples/maplibregl/AppMapLibreGl.svelte +++ /dev/null @@ -1,89 +0,0 @@ - - -
- - diff --git a/examples/maplibregl/index.html b/examples/maplibregl/index.html deleted file mode 100644 index 6a3ab31..0000000 --- a/examples/maplibregl/index.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - -MapTiler Geocoding Control :: MapLibre GL JS - -
- - diff --git a/examples/maplibregl/main.ts b/examples/maplibregl/main.ts deleted file mode 100644 index 6aa2d5c..0000000 --- a/examples/maplibregl/main.ts +++ /dev/null @@ -1,9 +0,0 @@ -import App from "./AppMapLibreGl.svelte"; - -const appElement = document.getElementById("app"); - -if (!appElement) { - throw new Error("element with id 'app' not found"); -} - -export default new App({ target: appElement }); diff --git a/examples/maptiler-sdk/AppMapTilerSdk.svelte b/examples/maptiler-sdk/AppMapTilerSdk.svelte deleted file mode 100644 index 9e641a9..0000000 --- a/examples/maptiler-sdk/AppMapTilerSdk.svelte +++ /dev/null @@ -1,61 +0,0 @@ - - -
- - diff --git a/examples/maptiler-sdk/index.html b/examples/maptiler-sdk/index.html deleted file mode 100644 index e025e77..0000000 --- a/examples/maptiler-sdk/index.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - -MapTiler Geocoding Control :: MapTiler SDK - -
- - diff --git a/examples/maptiler-sdk/main.ts b/examples/maptiler-sdk/main.ts deleted file mode 100644 index f04c8f1..0000000 --- a/examples/maptiler-sdk/main.ts +++ /dev/null @@ -1,9 +0,0 @@ -import App from "./AppMapTilerSdk.svelte"; - -const appElement = document.getElementById("app"); - -if (!appElement) { - throw new Error("element with id 'app' not found"); -} - -export default new App({ target: appElement }); diff --git a/examples/openlayers/AppOpenLayers.svelte b/examples/openlayers/AppOpenLayers.svelte deleted file mode 100644 index 444dec0..0000000 --- a/examples/openlayers/AppOpenLayers.svelte +++ /dev/null @@ -1,71 +0,0 @@ - - -
- - diff --git a/examples/openlayers/index.html b/examples/openlayers/index.html deleted file mode 100644 index aeeb83e..0000000 --- a/examples/openlayers/index.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - -MapTiler Geocoding Control :: OpenLayers - -
- - diff --git a/examples/openlayers/main.ts b/examples/openlayers/main.ts deleted file mode 100644 index 3fcfa06..0000000 --- a/examples/openlayers/main.ts +++ /dev/null @@ -1,9 +0,0 @@ -import App from "./AppOpenLayers.svelte"; - -const appElement = document.getElementById("app"); - -if (!appElement) { - throw new Error("element with id 'app' not found"); -} - -export default new App({ target: appElement }); diff --git a/examples/react/index.html b/examples/react/index.html deleted file mode 100644 index 97af800..0000000 --- a/examples/react/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - -MapTiler Geocoding Control :: React - -
- - diff --git a/examples/react/style.css b/examples/react/style.css deleted file mode 100644 index 5c172c7..0000000 --- a/examples/react/style.css +++ /dev/null @@ -1,48 +0,0 @@ -html, -body, -main { - height: 100%; - background-color: #eee; -} - -main { - padding: 1em; - display: flex; - flex-direction: column; -} - -.control-bar { - display: flex; - gap: 0.5em; - align-items: center; - flex-wrap: wrap; -} - -.flex-grow { - flex-grow: 1; -} - -.overflow-auto { - overflow: auto; -} - -.logs { - display: grid; - column-gap: 1em; - grid-template-columns: auto 1fr; - height: 0px; /* fixes overflow */ -} - -.logs > div:nth-child(2n) { - text-wrap: nowrap; - color: blue; -} - -select { - margin-right: 2ex; -} - -button.is-small { - padding: 4px 8px; - font-size: 0.8em; -} diff --git a/examples/standalone/leaflet.html b/examples/standalone/leaflet.html deleted file mode 100644 index 36d02ee..0000000 --- a/examples/standalone/leaflet.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - -
- - diff --git a/examples/standalone/maplibregl.html b/examples/standalone/maplibregl.html deleted file mode 100644 index 2291d04..0000000 --- a/examples/standalone/maplibregl.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - -
- - diff --git a/examples/standalone/ol.html b/examples/standalone/ol.html deleted file mode 100644 index 2e9d441..0000000 --- a/examples/standalone/ol.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - - - - -
- - diff --git a/examples/vanilla/AppVanilla.svelte b/examples/vanilla/AppVanilla.svelte deleted file mode 100644 index b4ab478..0000000 --- a/examples/vanilla/AppVanilla.svelte +++ /dev/null @@ -1,27 +0,0 @@ - - -
diff --git a/examples/vanilla/index.html b/examples/vanilla/index.html deleted file mode 100644 index 043f39f..0000000 --- a/examples/vanilla/index.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - -MapTiler Geocoding Control :: Vanilla JS - -
- - diff --git a/examples/vanilla/main.ts b/examples/vanilla/main.ts deleted file mode 100644 index 6fa1346..0000000 --- a/examples/vanilla/main.ts +++ /dev/null @@ -1,9 +0,0 @@ -import App from "./AppVanilla.svelte"; - -const appElement = document.getElementById("app"); - -if (!appElement) { - throw new Error("element with id 'app' not found"); -} - -export default new App({ target: appElement }); diff --git a/index.html b/index.html deleted file mode 100644 index 3076812..0000000 --- a/index.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - -MapTiler Geocoding Control - -

MapTiler Geocoding Control Examples

- -

Svelte

- - -

React

- - -

Vanilla JS (UMD)

- -

- Before opening the following examples first build the library with - npm run build. -

- - diff --git a/package-lock.json b/package-lock.json index dfc03cc..4986cb4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,63 +1,58 @@ { "name": "@maptiler/geocoding-control", - "version": "2.1.7", + "version": "3.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@maptiler/geocoding-control", - "version": "2.1.7", + "version": "3.0.0", "license": "BSD-3-Clause", "dependencies": { "@turf/bbox": "^7.2.0", - "@turf/clone": "^7.2.0", "@turf/difference": "^7.2.0", "@turf/flatten": "^7.2.0", + "@turf/helpers": "^7.2.0", "@turf/union": "^7.2.0", - "geo-coordinates-parser": "^1.7.4" + "@types/geojson": "^7946.0.16", + "geo-coordinates-parser": "^1.7.4", + "lit": "^3.3.1" }, "devDependencies": { - "@maptiler/sdk": "^3.0.1", - "@sveltejs/package": "^2.3.9", - "@sveltejs/vite-plugin-svelte": "^3.1.2", - "@tsconfig/svelte": "^5.0.4", - "@types/geojson": "^7946.0.16", - "@types/leaflet": "^1.9.16", - "@types/node": "^22.12.0", - "@types/react": "^19.0.8", - "@types/react-dom": "^19.0.3", - "concurrently": "^9.1.2", + "@canvas/image-data": "^1.1.0", + "@maptiler/sdk": "^3.8.0", + "@types/leaflet": "^1.9.21", + "@types/node": "ts5.8", + "@types/react": "^19.2.6", + "@types/react-dom": "^19.2.3", + "@vitest/web-worker": "^4.0.9", "dotenv": "^16.4.7", - "eslint": "^9.19.0", - "eslint-plugin-svelte": "^2.46.1", - "esm-env": "^1.2.2", - "globals": "^15.14.0", + "eslint": "^9.38.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.4", + "happy-dom": "^20.0.10", "husky": "^9.1.7", "leaflet": "^1.9.4", - "maplibre-gl": "^5.1.0", - "ol": "10.4", - "prettier": "^3.4.2", - "prettier-plugin-organize-imports": "^4.1.0", - "prettier-plugin-svelte": "^3.3.3", - "react": "^19.0.0", - "react-dom": "^19.0.0", - "replace-in-file": "^8.3.0", - "sass": "^1.83.4", - "svelte": "^4.2.19", - "svelte-check": "^4.1.4", - "svelte-preprocess": "^6.0.3", + "leaflet-v2": "npm:leaflet@2.0.0-alpha.1", + "ol": "^10.6.1", + "prettier": "^3.6.2", + "prettier-plugin-organize-imports": "^4.3.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", "tslib": "^2.8.1", - "typescript": "^5.7.3", - "typescript-eslint": "^8.22.0", - "vite": "^5.4.14" + "typescript": "~5.8.3", + "typescript-eslint": "^8.46.2", + "vite": "^7.1.12", + "vite-plugin-dts": "^4.5.4", + "vite-plugin-externalize-deps": "^0.10.0", + "vite-plugin-static-copy": "^3.1.4", + "vitest": "^4.0.8" }, "peerDependencies": { - "@maptiler/sdk": "^1 || ^2 || ^3", - "leaflet": "^1.7 || ^1.8 || ^1.9", - "maplibre-gl": "^2 || ^3 || ^4 || ^5", - "ol": "^6 || ^7 || ^8 || ^9 || ^10", - "react": "^17 || ^18 || ^19", - "svelte": "^4.2" + "@maptiler/sdk": "1 - 3", + "leaflet": "1.7 - 2", + "maplibre-gl": "2 - 5", + "ol": "6 - 10" }, "peerDependenciesMeta": { "@maptiler/sdk": { @@ -71,33 +66,70 @@ }, "ol": { "optional": true - }, - "react": { - "optional": true - }, - "svelte": { - "optional": true } } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" }, "engines": { "node": ">=6.0.0" } }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@canvas/image-data": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@canvas/image-data/-/image-data-1.1.0.tgz", + "integrity": "sha512-QdObRRjRbcXGmM1tmJ+MrHcaz1MftF2+W7YI+MsphnsCrmtyfS0d5qJbk0MeSbUeyM/jCb0hmnkXPsy026L7dA==", + "dev": true, + "license": "MIT" + }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz", + "integrity": "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==", "cpu": [ "ppc64" ], @@ -108,13 +140,13 @@ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.11.tgz", + "integrity": "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==", "cpu": [ "arm" ], @@ -125,13 +157,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.11.tgz", + "integrity": "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==", "cpu": [ "arm64" ], @@ -142,13 +174,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.11.tgz", + "integrity": "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==", "cpu": [ "x64" ], @@ -159,13 +191,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.11.tgz", + "integrity": "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==", "cpu": [ "arm64" ], @@ -176,13 +208,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.11.tgz", + "integrity": "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==", "cpu": [ "x64" ], @@ -193,13 +225,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.11.tgz", + "integrity": "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==", "cpu": [ "arm64" ], @@ -210,13 +242,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.11.tgz", + "integrity": "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==", "cpu": [ "x64" ], @@ -227,13 +259,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.11.tgz", + "integrity": "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==", "cpu": [ "arm" ], @@ -244,13 +276,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.11.tgz", + "integrity": "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==", "cpu": [ "arm64" ], @@ -261,13 +293,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.11.tgz", + "integrity": "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==", "cpu": [ "ia32" ], @@ -278,13 +310,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.11.tgz", + "integrity": "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==", "cpu": [ "loong64" ], @@ -295,13 +327,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.11.tgz", + "integrity": "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==", "cpu": [ "mips64el" ], @@ -312,13 +344,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.11.tgz", + "integrity": "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==", "cpu": [ "ppc64" ], @@ -329,13 +361,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.11.tgz", + "integrity": "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==", "cpu": [ "riscv64" ], @@ -346,13 +378,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.11.tgz", + "integrity": "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==", "cpu": [ "s390x" ], @@ -363,13 +395,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.11.tgz", + "integrity": "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==", "cpu": [ "x64" ], @@ -380,13 +412,30 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.11.tgz", + "integrity": "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.11.tgz", + "integrity": "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==", "cpu": [ "x64" ], @@ -397,13 +446,30 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.11.tgz", + "integrity": "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.11.tgz", + "integrity": "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==", "cpu": [ "x64" ], @@ -414,13 +480,30 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.11.tgz", + "integrity": "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.11.tgz", + "integrity": "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==", "cpu": [ "x64" ], @@ -431,13 +514,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.11.tgz", + "integrity": "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==", "cpu": [ "arm64" ], @@ -448,13 +531,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.11.tgz", + "integrity": "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==", "cpu": [ "ia32" ], @@ -465,13 +548,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.11.tgz", + "integrity": "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==", "cpu": [ "x64" ], @@ -482,13 +565,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", "dev": true, "license": "MIT", "dependencies": { @@ -518,9 +601,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, "license": "MIT", "engines": { @@ -528,13 +611,13 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz", - "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==", + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.5", + "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" }, @@ -542,10 +625,23 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/core": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz", - "integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -556,9 +652,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", - "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, "license": "MIT", "dependencies": { @@ -579,33 +675,23 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@eslint/js": { - "version": "9.19.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.19.0.tgz", - "integrity": "sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ==", + "version": "9.38.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.38.0.tgz", + "integrity": "sha512-UZ1VpFvXf9J06YG9xQBdnzU+kthors6KjhMAl6f4gH4usHyh31rUf2DLGInT8RFYIReYXNSydgPY0V2LuWgl7A==", "dev": true, "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, "node_modules/@eslint/object-schema": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz", - "integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -613,13 +699,13 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz", - "integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.10.0", + "@eslint/core": "^0.17.0", "levn": "^0.4.1" }, "engines": { @@ -637,33 +723,19 @@ } }, "node_modules/@humanfs/node": { - "version": "0.16.6", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", - "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", "dev": true, "license": "Apache-2.0", "dependencies": { "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.3.0" + "@humanwhocodes/retry": "^0.4.0" }, "engines": { "node": ">=18.18.0" } }, - "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -679,9 +751,9 @@ } }, "node_modules/@humanwhocodes/retry": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", - "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -692,138 +764,56 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": "20 || >=22" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" + "@isaacs/balanced-match": "^4.0.1" }, "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" + "node": "20 || >=22" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "dev": true, "license": "MIT" }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "license": "MIT", + "node_modules/@lit-labs/ssr-dom-shim": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.4.0.tgz", + "integrity": "sha512-ficsEARKnmmW5njugNYKipTm4SFnbik7CXtoencDZzmzo/dQ+2Q0bgkzJuoJP20Aj0F+izzJjOqsnkd6F/o1bw==", + "license": "BSD-3-Clause" + }, + "node_modules/@lit/reactive-element": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.1.1.tgz", + "integrity": "sha512-N+dm5PAYdQ8e6UlywyyrgI2t++wFGXfHx+dSJ1oBrg6FAxUj40jId++EaRm80MKX5JnlH1sBsyZ5h0bcZKemCg==", + "license": "BSD-3-Clause", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@lit-labs/ssr-dom-shim": "^1.4.0" } }, "node_modules/@mapbox/geojson-rewind": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz", "integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "get-stream": "^6.0.1", @@ -833,74 +823,63 @@ "geojson-rewind": "geojson-rewind" } }, - "node_modules/@mapbox/geojson-rewind/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@mapbox/jsonlint-lines-primitives": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", - "dev": true, + "devOptional": true, "engines": { "node": ">= 0.6" } }, "node_modules/@mapbox/point-geometry": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", - "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==", - "dev": true, + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-1.1.0.tgz", + "integrity": "sha512-YGcBz1cg4ATXDCM/71L9xveh4dynfGmcLDqufR+nQQy3fKwsAZsWd/x4621/6uJaeB9mwOHE6hPeDgXz9uViUQ==", + "devOptional": true, "license": "ISC" }, "node_modules/@mapbox/tiny-sdf": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.6.tgz", - "integrity": "sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA==", - "dev": true, + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.7.tgz", + "integrity": "sha512-25gQLQMcpivjOSA40g3gO6qgiFPDpWRoMfd+G/GoppPIeP6JDaMMkMrEJnMZhKyyS6iKwVt5YKu02vCUyJM3Ug==", + "devOptional": true, "license": "BSD-2-Clause" }, "node_modules/@mapbox/unitbezier": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause" }, "node_modules/@mapbox/vector-tile": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz", - "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", - "dev": true, + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-2.0.4.tgz", + "integrity": "sha512-AkOLcbgGTdXScosBWwmmD7cDlvOjkg/DetGva26pIRiZPdeJYjYKarIlb4uxVzi6bwHO6EWH82eZ5Nuv4T5DUg==", + "devOptional": true, "license": "BSD-3-Clause", "dependencies": { - "@mapbox/point-geometry": "~0.1.0" + "@mapbox/point-geometry": "~1.1.0", + "@types/geojson": "^7946.0.16", + "pbf": "^4.0.1" } }, "node_modules/@mapbox/whoots-js": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==", - "dev": true, + "devOptional": true, "license": "ISC", "engines": { "node": ">=6.0.0" } }, "node_modules/@maplibre/maplibre-gl-style-spec": { - "version": "23.1.0", - "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-23.1.0.tgz", - "integrity": "sha512-R6/ihEuC5KRexmKIYkWqUv84Gm+/QwsOUgHyt1yy2XqCdGdLvlBWVWIIeTZWN4NGdwmY6xDzdSGU2R9oBLNg2w==", - "dev": true, + "version": "23.3.0", + "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-23.3.0.tgz", + "integrity": "sha512-IGJtuBbaGzOUgODdBRg66p8stnwj9iDXkgbYKoYcNiiQmaez5WVRfXm4b03MCDwmZyX93csbfHFWEJJYHnn5oA==", + "devOptional": true, "license": "ISC", "dependencies": { "@mapbox/jsonlint-lines-primitives": "~2.0.2", @@ -917,10 +896,26 @@ "gl-style-validate": "dist/gl-style-validate.mjs" } }, + "node_modules/@maplibre/vt-pbf": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@maplibre/vt-pbf/-/vt-pbf-4.0.3.tgz", + "integrity": "sha512-YsW99BwnT+ukJRkseBcLuZHfITB4puJoxnqPVjo72rhW/TaawVYsgQHcqWLzTxqknttYoDpgyERzWSa/XrETdA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@mapbox/point-geometry": "^1.1.0", + "@mapbox/vector-tile": "^2.0.4", + "@types/geojson-vt": "3.2.5", + "@types/supercluster": "^7.1.3", + "geojson-vt": "^4.0.2", + "pbf": "^4.0.1", + "supercluster": "^8.0.1" + } + }, "node_modules/@maptiler/client": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@maptiler/client/-/client-2.2.0.tgz", - "integrity": "sha512-kV4dSJK2PLfRLnl437CQgDJBboHcf+Z7FWkSoPW3ANca/csoYQQOwz42BPNkda/98OT+CviIueeQdNUyeEL1OQ==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@maptiler/client/-/client-2.5.1.tgz", + "integrity": "sha512-2rveqohOu3xv16EX65rFUQF8fpPppefrGkvUEtZOx50EDHFxrhEVjKM0p95TuT0RLygxF/sw4vAqUFCBOnPbiw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -928,20 +923,148 @@ } }, "node_modules/@maptiler/sdk": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@maptiler/sdk/-/sdk-3.0.1.tgz", - "integrity": "sha512-81CeL/brKTY0Qp1SPd6aexaXUpFAmsoLaPFi62zugdG/hUYuavBupLirF+qnOJOW6j+MWFWLdsUFRaORtRrKzQ==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@maptiler/sdk/-/sdk-3.8.0.tgz", + "integrity": "sha512-oXLlSyJhKADB1KTfxj5bhnRml3nrvBerhuuo1v+rDJKrUHqQpVPj6PS+z809D/+UB9ZwzzHOBeFZP3vYCK3U5g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "@maplibre/maplibre-gl-style-spec": "^23.0.0", - "@maptiler/client": "^2.2.0", + "@maplibre/maplibre-gl-style-spec": "~23.3.0", + "@maptiler/client": "~2.5.1", "events": "^3.3.0", + "gl-matrix": "^3.4.3", "js-base64": "^3.7.7", - "maplibre-gl": "^5.0.1", + "maplibre-gl": "~5.6.0", "uuid": "^11.0.5" } }, + "node_modules/@microsoft/api-extractor": { + "version": "7.53.3", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.53.3.tgz", + "integrity": "sha512-p2HmQaMSVqMBj3bH3643f8xApKAqrF1jNpPsMCTQOYCYgfwLnvzsve8c+bgBWzCOBBgLK54PB6ZLIWMGLg8CZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/api-extractor-model": "7.31.3", + "@microsoft/tsdoc": "~0.15.1", + "@microsoft/tsdoc-config": "~0.17.1", + "@rushstack/node-core-library": "5.18.0", + "@rushstack/rig-package": "0.6.0", + "@rushstack/terminal": "0.19.3", + "@rushstack/ts-command-line": "5.1.3", + "lodash": "~4.17.15", + "minimatch": "10.0.3", + "resolve": "~1.22.1", + "semver": "~7.5.4", + "source-map": "~0.6.1", + "typescript": "5.8.2" + }, + "bin": { + "api-extractor": "bin/api-extractor" + } + }, + "node_modules/@microsoft/api-extractor-model": { + "version": "7.31.3", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.31.3.tgz", + "integrity": "sha512-dv4quQI46p0U03TCEpasUf6JrJL3qjMN7JUAobsPElxBv4xayYYvWW9aPpfYV+Jx6hqUcVaLVOeV7+5hxsyoFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "~0.15.1", + "@microsoft/tsdoc-config": "~0.17.1", + "@rushstack/node-core-library": "5.18.0" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/minimatch": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", + "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/typescript": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@microsoft/tsdoc": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.15.1.tgz", + "integrity": "sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@microsoft/tsdoc-config": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.17.1.tgz", + "integrity": "sha512-UtjIFe0C6oYgTnad4q1QP4qXwLhe6tIpNTRStJ2RZEPIkqQPREAwE5spzVxsdn9UaEMUqhh0AqSx3X4nWAKXWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "0.15.1", + "ajv": "~8.12.0", + "jju": "~1.4.0", + "resolve": "~1.22.2" + } + }, + "node_modules/@microsoft/tsdoc-config/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@microsoft/tsdoc-config/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -980,68 +1103,94 @@ "node": ">= 8" } }, - "node_modules/@parcel/watcher": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", - "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "node_modules/@petamoriken/float16": { + "version": "3.9.3", + "resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.9.3.tgz", + "integrity": "sha512-8awtpHXCx/bNpFt4mt2xdkgtgVvKqty8VbjHI/WWWQuEw+KLzFot3f4+LkQY9YmOtq7A5GdOnqoIC8Pdygjk2g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "optional": true, "dependencies": { - "detect-libc": "^1.0.3", - "is-glob": "^4.0.3", - "micromatch": "^4.0.5", - "node-addon-api": "^7.0.0" + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" }, "engines": { - "node": ">= 10.0.0" + "node": ">=14.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, - "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.1", - "@parcel/watcher-darwin-arm64": "2.5.1", - "@parcel/watcher-darwin-x64": "2.5.1", - "@parcel/watcher-freebsd-x64": "2.5.1", - "@parcel/watcher-linux-arm-glibc": "2.5.1", - "@parcel/watcher-linux-arm-musl": "2.5.1", - "@parcel/watcher-linux-arm64-glibc": "2.5.1", - "@parcel/watcher-linux-arm64-musl": "2.5.1", - "@parcel/watcher-linux-x64-glibc": "2.5.1", - "@parcel/watcher-linux-x64-musl": "2.5.1", - "@parcel/watcher-win32-arm64": "2.5.1", - "@parcel/watcher-win32-ia32": "2.5.1", - "@parcel/watcher-win32-x64": "2.5.1" - } - }, - "node_modules/@parcel/watcher-android-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", - "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz", + "integrity": "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==", "cpu": [ - "arm64" + "arm" ], "dev": true, "license": "MIT", "optional": true, "os": [ "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz", + "integrity": "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==", + "cpu": [ + "arm64" ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] }, - "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", - "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz", + "integrity": "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==", "cpu": [ "arm64" ], @@ -1050,19 +1199,12 @@ "optional": true, "os": [ "darwin" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + ] }, - "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", - "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz", + "integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==", "cpu": [ "x64" ], @@ -1071,19 +1213,26 @@ "optional": true, "os": [ "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz", + "integrity": "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==", + "cpu": [ + "arm64" ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", - "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz", + "integrity": "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==", "cpu": [ "x64" ], @@ -1092,19 +1241,12 @@ "optional": true, "os": [ "freebsd" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + ] }, - "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", - "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz", + "integrity": "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==", "cpu": [ "arm" ], @@ -1113,19 +1255,12 @@ "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + ] }, - "node_modules/@parcel/watcher-linux-arm-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", - "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz", + "integrity": "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==", "cpu": [ "arm" ], @@ -1134,19 +1269,12 @@ "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + ] }, - "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", - "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz", + "integrity": "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==", "cpu": [ "arm64" ], @@ -1155,19 +1283,12 @@ "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + ] }, - "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", - "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz", + "integrity": "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==", "cpu": [ "arm64" ], @@ -1176,184 +1297,82 @@ "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + ] }, - "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", - "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.5.tgz", + "integrity": "sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==", "cpu": [ - "x64" + "loong64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + ] }, - "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", - "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.5.tgz", + "integrity": "sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==", "cpu": [ - "x64" + "ppc64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + ] }, - "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", - "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz", + "integrity": "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==", "cpu": [ - "arm64" + "riscv64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + "linux" + ] }, - "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", - "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.5.tgz", + "integrity": "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==", "cpu": [ - "ia32" + "riscv64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + "linux" + ] }, - "node_modules/@parcel/watcher-win32-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", - "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz", + "integrity": "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==", "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@petamoriken/float16": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.9.1.tgz", - "integrity": "sha512-j+ejhYwY6PeB+v1kn7lZFACUIG97u90WxMuGosILFsl9d4Ovi0sjk0GlPfoEcx+FzvXZDAfioD+NGnnPamXgMA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.32.1.tgz", - "integrity": "sha512-/pqA4DmqyCm8u5YIDzIdlLcEmuvxb0v8fZdFhVMszSpDTgbQKdw3/mB3eMUHIbubtJ6F9j+LtmyCnHTEqIHyzA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.32.1.tgz", - "integrity": "sha512-If3PDskT77q7zgqVqYuj7WG3WC08G1kwXGVFi9Jr8nY6eHucREHkfpX79c0ACAjLj3QIWKPJR7w4i+f5EdLH5Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.32.1.tgz", - "integrity": "sha512-zCpKHioQ9KgZToFp5Wvz6zaWbMzYQ2LJHQ+QixDKq52KKrF65ueu6Af4hLlLWHjX1Wf/0G5kSJM9PySW9IrvHA==", - "cpu": [ - "arm64" + "s390x" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "darwin" + "linux" ] }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.32.1.tgz", - "integrity": "sha512-sFvF+t2+TyUo/ZQqUcifrJIgznx58oFZbdHS9TvHq3xhPVL9nOp+yZ6LKrO9GWTP+6DbFtoyLDbjTpR62Mbr3Q==", + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz", + "integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==", "cpu": [ "x64" ], @@ -1361,69 +1380,41 @@ "license": "MIT", "optional": true, "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.32.1.tgz", - "integrity": "sha512-NbOa+7InvMWRcY9RG+B6kKIMD/FsnQPH0MWUvDlQB1iXnF/UcKSudCXZtv4lW+C276g3w5AxPbfry5rSYvyeYA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" + "linux" ] }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.32.1.tgz", - "integrity": "sha512-JRBRmwvHPXR881j2xjry8HZ86wIPK2CcDw0EXchE1UgU0ubWp9nvlT7cZYKc6bkypBt745b4bglf3+xJ7hXWWw==", + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz", + "integrity": "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==", "cpu": [ "x64" ], "dev": true, "license": "MIT", "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.32.1.tgz", - "integrity": "sha512-PKvszb+9o/vVdUzCCjL0sKHukEQV39tD3fepXxYrHE3sTKrRdCydI7uldRLbjLmDA3TFDmh418XH19NOsDRH8g==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, "os": [ "linux" ] }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.32.1.tgz", - "integrity": "sha512-9WHEMV6Y89eL606ReYowXuGF1Yb2vwfKWKdD1A5h+OYnPZSJvxbEjxTRKPgi7tkP2DSnW0YLab1ooy+i/FQp/Q==", + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.5.tgz", + "integrity": "sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==", "cpu": [ - "arm" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "openharmony" ] }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.32.1.tgz", - "integrity": "sha512-tZWc9iEt5fGJ1CL2LRPw8OttkCBDs+D8D3oEM8mH8S1ICZCtFJhD7DZ3XMGM8kpqHvhGUTvNUYVDnmkj4BDXnw==", + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz", + "integrity": "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==", "cpu": [ "arm64" ], @@ -1431,217 +1422,220 @@ "license": "MIT", "optional": true, "os": [ - "linux" + "win32" ] }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.32.1.tgz", - "integrity": "sha512-FTYc2YoTWUsBz5GTTgGkRYYJ5NGJIi/rCY4oK/I8aKowx1ToXeoVVbIE4LGAjsauvlhjfl0MYacxClLld1VrOw==", + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz", + "integrity": "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==", "cpu": [ - "arm64" + "ia32" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "win32" ] }, - "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.32.1.tgz", - "integrity": "sha512-F51qLdOtpS6P1zJVRzYM0v6MrBNypyPEN1GfMiz0gPu9jN8ScGaEFIZQwteSsGKg799oR5EaP7+B2jHgL+d+Kw==", + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.5.tgz", + "integrity": "sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==", "cpu": [ - "loong64" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "win32" ] }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.32.1.tgz", - "integrity": "sha512-wO0WkfSppfX4YFm5KhdCCpnpGbtgQNj/tgvYzrVYFKDpven8w2N6Gg5nB6w+wAMO3AIfSTWeTjfVe+uZ23zAlg==", + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz", + "integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==", "cpu": [ - "ppc64" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "win32" ] }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.32.1.tgz", - "integrity": "sha512-iWswS9cIXfJO1MFYtI/4jjlrGb/V58oMu4dYJIKnR5UIwbkzR0PJ09O0PDZT0oJ3LYWXBSWahNf/Mjo6i1E5/g==", - "cpu": [ - "riscv64" - ], + "node_modules/@rushstack/node-core-library": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.18.0.tgz", + "integrity": "sha512-XDebtBdw5S3SuZIt+Ra2NieT8kQ3D2Ow1HxhDQ/2soinswnOu9e7S69VSwTOLlQnx5mpWbONu+5JJjDxMAb6Fw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "ajv": "~8.13.0", + "ajv-draft-04": "~1.0.0", + "ajv-formats": "~3.0.1", + "fs-extra": "~11.3.0", + "import-lazy": "~4.0.0", + "jju": "~1.4.0", + "resolve": "~1.22.1", + "semver": "~7.5.4" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.32.1.tgz", - "integrity": "sha512-RKt8NI9tebzmEthMnfVgG3i/XeECkMPS+ibVZjZ6mNekpbbUmkNWuIN2yHsb/mBPyZke4nlI4YqIdFPgKuoyQQ==", - "cpu": [ - "s390x" - ], + "node_modules/@rushstack/node-core-library/node_modules/ajv": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", + "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.32.1.tgz", - "integrity": "sha512-WQFLZ9c42ECqEjwg/GHHsouij3pzLXkFdz0UxHa/0OM12LzvX7DzedlY0SIEly2v18YZLRhCRoHZDxbBSWoGYg==", - "cpu": [ - "x64" - ], + "node_modules/@rushstack/node-core-library/node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "peerDependencies": { + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.32.1.tgz", - "integrity": "sha512-BLoiyHDOWoS3uccNSADMza6V6vCNiphi94tQlVIL5de+r6r/CCQuNnerf+1g2mnk2b6edp5dk0nhdZ7aEjOBsA==", - "cpu": [ - "x64" - ], + "node_modules/@rushstack/node-core-library/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "license": "MIT" }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.32.1.tgz", - "integrity": "sha512-w2l3UnlgYTNNU+Z6wOR8YdaioqfEnwPjIsJ66KxKAf0p+AuL2FHeTX6qvM+p/Ue3XPBVNyVSfCrfZiQh7vZHLQ==", - "cpu": [ - "arm64" - ], + "node_modules/@rushstack/node-core-library/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.32.1.tgz", - "integrity": "sha512-Am9H+TGLomPGkBnaPWie4F3x+yQ2rr4Bk2jpwy+iV+Gel9jLAu/KqT8k3X4jxFPW6Zf8OMnehyutsd+eHoq1WQ==", - "cpu": [ - "ia32" - ], + "node_modules/@rushstack/problem-matcher": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@rushstack/problem-matcher/-/problem-matcher-0.1.1.tgz", + "integrity": "sha512-Fm5XtS7+G8HLcJHCWpES5VmeMyjAKaWeyZU5qPzZC+22mPlJzAsOxymHiWIfuirtPckX3aptWws+K2d0BzniJA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.32.1.tgz", - "integrity": "sha512-ar80GhdZb4DgmW3myIS9nRFYcpJRSME8iqWgzH2i44u+IdrzmiXVxeFnExQ5v4JYUSpg94bWjevMG8JHf1Da5Q==", - "cpu": [ - "x64" - ], + "node_modules/@rushstack/rig-package": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.6.0.tgz", + "integrity": "sha512-ZQmfzsLE2+Y91GF15c65L/slMRVhF6Hycq04D4TwtdGaUAbIXXg9c5pKA5KFU7M4QMaihoobp9JJYpYcaY3zOw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "resolve": "~1.22.1", + "strip-json-comments": "~3.1.1" + } }, - "node_modules/@sveltejs/package": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@sveltejs/package/-/package-2.3.9.tgz", - "integrity": "sha512-POIiQknGmcGCcM7ZbFG7cjsJ51GndFOY3PTXa8XFzZ+C/GJfx/JufvVXiWcXVsteP74FeXSSgcC+b5sIayXXKw==", + "node_modules/@rushstack/terminal": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.19.3.tgz", + "integrity": "sha512-0P8G18gK9STyO+CNBvkKPnWGMxESxecTYqOcikHOVIHXa9uAuTK+Fw8TJq2Gng1w7W6wTC9uPX6hGNvrMll2wA==", "dev": true, "license": "MIT", "dependencies": { - "chokidar": "^4.0.0", - "kleur": "^4.1.5", - "sade": "^1.8.1", - "semver": "^7.5.4", - "svelte2tsx": "~0.7.33" - }, - "bin": { - "svelte-package": "svelte-package.js" - }, - "engines": { - "node": "^16.14 || >=18" + "@rushstack/node-core-library": "5.18.0", + "@rushstack/problem-matcher": "0.1.1", + "supports-color": "~8.1.1" }, "peerDependencies": { - "svelte": "^3.44.0 || ^4.0.0 || ^5.0.0-next.1" + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@sveltejs/vite-plugin-svelte": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.1.2.tgz", - "integrity": "sha512-Txsm1tJvtiYeLUVRNqxZGKR/mI+CzuIQuc2gn+YCs9rMTowpNZ2Nqt53JdL8KF9bLhAf2ruR/dr9eZCwdTriRA==", + "node_modules/@rushstack/terminal/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "license": "MIT", "dependencies": { - "@sveltejs/vite-plugin-svelte-inspector": "^2.1.0", - "debug": "^4.3.4", - "deepmerge": "^4.3.1", - "kleur": "^4.1.5", - "magic-string": "^0.30.10", - "svelte-hmr": "^0.16.0", - "vitefu": "^0.2.5" + "has-flag": "^4.0.0" }, "engines": { - "node": "^18.0.0 || >=20" + "node": ">=10" }, - "peerDependencies": { - "svelte": "^4.0.0 || ^5.0.0-next.0", - "vite": "^5.0.0" + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/@sveltejs/vite-plugin-svelte-inspector": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.1.0.tgz", - "integrity": "sha512-9QX28IymvBlSCqsCll5t0kQVxipsfhFFL+L2t3nTWfXnddYwxBuAEtTtlaVQpRz9c37BhJjltSeY4AJSC03SSg==", + "node_modules/@rushstack/ts-command-line": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-5.1.3.tgz", + "integrity": "sha512-Kdv0k/BnnxIYFlMVC1IxrIS0oGQd4T4b7vKfx52Y2+wk2WZSDFIvedr7JrhenzSlm3ou5KwtoTGTGd5nbODRug==", "dev": true, "license": "MIT", "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.0.0 || >=20" - }, - "peerDependencies": { - "@sveltejs/vite-plugin-svelte": "^3.0.0", - "svelte": "^4.0.0 || ^5.0.0-next.0", - "vite": "^5.0.0" + "@rushstack/terminal": "0.19.3", + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "string-argv": "~0.3.1" + } + }, + "node_modules/@rushstack/ts-command-line/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" } }, - "node_modules/@tsconfig/svelte": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-5.0.4.tgz", - "integrity": "sha512-BV9NplVgLmSi4mwKzD8BD/NQ8erOY/nUE/GpgWe2ckx+wIQF5RyRirn/QsSSCPeulVpc3RA/iJt6DpfTIZps0Q==", + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", "dev": true, "license": "MIT" }, @@ -1660,20 +1654,6 @@ "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/clone": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-7.2.0.tgz", - "integrity": "sha512-JlGUT+/5qoU5jqZmf6NMFIoLDY3O7jKd53Up+zbpJ2vzUp6QdwdNzwrsCeONhynWM13F0MVtPXH4AtdkrgFk4g==", - "license": "MIT", - "dependencies": { - "@turf/helpers": "^7.2.0", - "@types/geojson": "^7946.0.10", - "tslib": "^2.8.1" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, "node_modules/@turf/difference": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@turf/difference/-/difference-7.2.0.tgz", @@ -1747,82 +1727,81 @@ "url": "https://opencollective.com/turf" } }, - "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "node_modules/@types/argparse": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz", + "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", "dev": true, "license": "MIT" }, - "node_modules/@types/geojson": { - "version": "7946.0.16", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", - "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", - "license": "MIT" - }, - "node_modules/@types/geojson-vt": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/@types/geojson-vt/-/geojson-vt-3.2.5.tgz", - "integrity": "sha512-qDO7wqtprzlpe8FfQ//ClPV9xiuoh2nkIgiouIptON9w5jvD/fA4szvP9GBlDVdJ5dldAl0kX/sy3URbWwLx0g==", + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", "dev": true, "license": "MIT", "dependencies": { - "@types/geojson": "*" + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" } }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", "dev": true, "license": "MIT" }, - "node_modules/@types/leaflet": { - "version": "1.9.16", - "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.16.tgz", - "integrity": "sha512-wzZoyySUxkgMZ0ihJ7IaUIblG8Rdc8AbbZKLneyn+QjYsj5q1QU7TEKYqwTr10BGSzY5LI7tJk9Ifo+mEjdFRw==", + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, + "license": "MIT" + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, + "node_modules/@types/geojson-vt": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@types/geojson-vt/-/geojson-vt-3.2.5.tgz", + "integrity": "sha512-qDO7wqtprzlpe8FfQ//ClPV9xiuoh2nkIgiouIptON9w5jvD/fA4szvP9GBlDVdJ5dldAl0kX/sy3URbWwLx0g==", + "devOptional": true, "license": "MIT", "dependencies": { "@types/geojson": "*" } }, - "node_modules/@types/mapbox__point-geometry": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@types/mapbox__point-geometry/-/mapbox__point-geometry-0.1.4.tgz", - "integrity": "sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA==", + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, "license": "MIT" }, - "node_modules/@types/mapbox__vector-tile": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@types/mapbox__vector-tile/-/mapbox__vector-tile-1.3.4.tgz", - "integrity": "sha512-bpd8dRn9pr6xKvuEBQup8pwQfD4VUyqO/2deGjfpe6AwC8YRlyEipvefyRJUSiCJTZuCb8Pl1ciVV5ekqJ96Bg==", + "node_modules/@types/leaflet": { + "version": "1.9.21", + "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.21.tgz", + "integrity": "sha512-TbAd9DaPGSnzp6QvtYngntMZgcRk+igFELwR2N99XZn7RXUdKgsXMR+28bUO0rPsWp8MIu/f47luLIQuSLYv/w==", "dev": true, "license": "MIT", "dependencies": { - "@types/geojson": "*", - "@types/mapbox__point-geometry": "*", - "@types/pbf": "*" + "@types/geojson": "*" } }, "node_modules/@types/node": { - "version": "22.12.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.12.0.tgz", - "integrity": "sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==", + "version": "24.9.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.2.tgz", + "integrity": "sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.20.0" + "undici-types": "~7.16.0" } }, - "node_modules/@types/pbf": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.5.tgz", - "integrity": "sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/rbush": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/rbush/-/rbush-4.0.0.tgz", @@ -1831,51 +1810,64 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "19.0.8", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.8.tgz", - "integrity": "sha512-9P/o1IGdfmQxrujGbIMDyYaaCykhLKc0NGCtYcECNUr9UAaDe4gwvV9bR6tvd5Br1SG0j+PBpbKr2UYY8CwqSw==", + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.6.tgz", + "integrity": "sha512-p/jUvulfgU7oKtj6Xpk8cA2Y1xKTtICGpJYeJXz2YVO2UcvjQgeRMLDGfDeqeRW2Ta+0QNFwcc8X3GH8SxZz6w==", "dev": true, "license": "MIT", "dependencies": { - "csstype": "^3.0.2" + "csstype": "^3.2.2" } }, "node_modules/@types/react-dom": { - "version": "19.0.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.3.tgz", - "integrity": "sha512-0Knk+HJiMP/qOZgMyNFamlIjw9OFCsyC2ZbigmEEyXXixgre6IQpm/4V+r3qH4GC1JPvRJKInw+on2rV6YZLeA==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "dev": true, "license": "MIT", "peerDependencies": { - "@types/react": "^19.0.0" + "@types/react": "^19.2.0" } }, "node_modules/@types/supercluster": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/supercluster/-/supercluster-7.1.3.tgz", "integrity": "sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@types/geojson": "*" } }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT" + }, + "node_modules/@types/whatwg-mimetype": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-mimetype/-/whatwg-mimetype-3.0.2.tgz", + "integrity": "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==", + "dev": true, + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.22.0.tgz", - "integrity": "sha512-4Uta6REnz/xEJMvwf72wdUnC3rr4jAQf5jnTkeRQ9b6soxLxhDEbS/pfMPoJLDfFPNVRdryqWUIV/2GZzDJFZw==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.2.tgz", + "integrity": "sha512-ZGBMToy857/NIPaaCucIUQgqueOiq7HeAKkhlvqVV4lm089zUFW6ikRySx2v+cAhKeUCPuWVHeimyk6Dw1iY3w==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.22.0", - "@typescript-eslint/type-utils": "8.22.0", - "@typescript-eslint/utils": "8.22.0", - "@typescript-eslint/visitor-keys": "8.22.0", + "@typescript-eslint/scope-manager": "8.46.2", + "@typescript-eslint/type-utils": "8.46.2", + "@typescript-eslint/utils": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2", "graphemer": "^1.4.0", - "ignore": "^5.3.1", + "ignore": "^7.0.0", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.0.0" + "ts-api-utils": "^2.1.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1885,22 +1877,55 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "@typescript-eslint/parser": "^8.46.2", "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.22.0.tgz", - "integrity": "sha512-MqtmbdNEdoNxTPzpWiWnqNac54h8JDAmkWtJExBVVnSrSmi9z+sZUt0LfKqk9rjqmKOIeRhO4fHHJ1nQIjduIQ==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.2.tgz", + "integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.2.tgz", + "integrity": "sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.22.0", - "@typescript-eslint/types": "8.22.0", - "@typescript-eslint/typescript-estree": "8.22.0", - "@typescript-eslint/visitor-keys": "8.22.0", + "@typescript-eslint/tsconfig-utils": "^8.46.2", + "@typescript-eslint/types": "^8.46.2", "debug": "^4.3.4" }, "engines": { @@ -1910,105 +1935,419 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.2.tgz", + "integrity": "sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.2.tgz", + "integrity": "sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.2.tgz", + "integrity": "sha512-HbPM4LbaAAt/DjxXaG9yiS9brOOz6fabal4uvUmaUYe6l3K1phQDMQKBRUrr06BQkxkvIZVVHttqiybM9nJsLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2", + "@typescript-eslint/utils": "8.46.2", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.2.tgz", + "integrity": "sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.2.tgz", + "integrity": "sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.46.2", + "@typescript-eslint/tsconfig-utils": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.2.tgz", + "integrity": "sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.2.tgz", + "integrity": "sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitest/expect": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.9.tgz", + "integrity": "sha512-C2vyXf5/Jfj1vl4DQYxjib3jzyuswMi/KHHVN2z+H4v16hdJ7jMZ0OGe3uOVIt6LyJsAofDdaJNIFEpQcrSTFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.9", + "@vitest/utils": "4.0.9", + "chai": "^6.2.0", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.9.tgz", + "integrity": "sha512-PUyaowQFHW+9FKb4dsvvBM4o025rWMlEDXdWRxIOilGaHREYTi5Q2Rt9VCgXgPy/hHZu1LeuXtrA/GdzOatP2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.0.9", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/mocker/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.9.tgz", + "integrity": "sha512-Hor0IBTwEi/uZqB7pvGepyElaM8J75pYjrrqbC8ZYMB9/4n5QA63KC15xhT+sqHpdGWfdnPo96E8lQUxs2YzSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.9.tgz", + "integrity": "sha512-aF77tsXdEvIJRkj9uJZnHtovsVIx22Ambft9HudC+XuG/on1NY/bf5dlDti1N35eJT+QZLb4RF/5dTIG18s98w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.0.9", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.9.tgz", + "integrity": "sha512-r1qR4oYstPbnOjg0Vgd3E8ADJbi4ditCzqr+Z9foUrRhIy778BleNyZMeAJ2EjV+r4ASAaDsdciC9ryMy8xMMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.9", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.9.tgz", + "integrity": "sha512-J9Ttsq0hDXmxmT8CUOWUr1cqqAj2FJRGTdyEjSR+NjoOGKEqkEWj+09yC0HhI8t1W6t4Ctqawl1onHgipJve1A==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.9.tgz", + "integrity": "sha512-cEol6ygTzY4rUPvNZM19sDf7zGa35IYTm9wfzkHoT/f5jX10IOY7QleWSOh5T0e3I3WVozwK5Asom79qW8DiuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.9", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/web-worker": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@vitest/web-worker/-/web-worker-4.0.9.tgz", + "integrity": "sha512-rAX5p1S1ZE9ZAzTDkk7N0l1L0y5V5QLc/xKXwhS2X/GuIdDxrJQHXsmY65HR51x9p3LU0OgaeZu+x1rh1dLP+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "4.0.9" + } + }, + "node_modules/@volar/language-core": { + "version": "2.4.23", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.23.tgz", + "integrity": "sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.23" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.23", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.23.tgz", + "integrity": "sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.23", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.23.tgz", + "integrity": "sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.23", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.22.0.tgz", - "integrity": "sha512-/lwVV0UYgkj7wPSw0o8URy6YI64QmcOdwHuGuxWIYznO6d45ER0wXUbksr9pYdViAofpUCNJx/tAzNukgvaaiQ==", + "node_modules/@vue/compiler-core": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.22.tgz", + "integrity": "sha512-jQ0pFPmZwTEiRNSb+i9Ow/I/cHv2tXYqsnHKKyCQ08irI2kdF5qmYedmF8si8mA7zepUFmJ2hqzS8CQmNOWOkQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.22.0", - "@typescript-eslint/visitor-keys": "8.22.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "@babel/parser": "^7.28.4", + "@vue/shared": "3.5.22", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.22.0.tgz", - "integrity": "sha512-NzE3aB62fDEaGjaAYZE4LH7I1MUwHooQ98Byq0G0y3kkibPJQIXVUspzlFOmOfHhiDLwKzMlWxaNv+/qcZurJA==", + "node_modules/@vue/compiler-dom": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.22.tgz", + "integrity": "sha512-W8RknzUM1BLkypvdz10OVsGxnMAuSIZs9Wdx1vzA3mL5fNMN15rhrSCLiTm6blWeACwUwizzPVqGJgOGBEN/hA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.22.0", - "@typescript-eslint/utils": "8.22.0", - "debug": "^4.3.4", - "ts-api-utils": "^2.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "@vue/compiler-core": "3.5.22", + "@vue/shared": "3.5.22" } }, - "node_modules/@typescript-eslint/types": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.22.0.tgz", - "integrity": "sha512-0S4M4baNzp612zwpD4YOieP3VowOARgK2EkN/GBn95hpyF8E2fbMT55sRHWBq+Huaqk3b3XK+rxxlM8sPgGM6A==", + "node_modules/@vue/compiler-vue2": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", + "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", "dev": true, "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.22.0.tgz", - "integrity": "sha512-SJX99NAS2ugGOzpyhMza/tX+zDwjvwAtQFLsBo3GQxiGcvaKlqGBkmZ+Y1IdiSi9h4Q0Lr5ey+Cp9CGWNY/F/w==", + "node_modules/@vue/language-core": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.0.tgz", + "integrity": "sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.22.0", - "@typescript-eslint/visitor-keys": "8.22.0", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "@volar/language-core": "~2.4.11", + "@vue/compiler-dom": "^3.5.0", + "@vue/compiler-vue2": "^2.7.16", + "@vue/shared": "^3.5.0", + "alien-signals": "^0.4.9", + "minimatch": "^9.0.3", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.8.0" + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "node_modules/@vue/language-core/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "node_modules/@vue/language-core/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", @@ -2024,52 +2363,17 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@typescript-eslint/utils": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.22.0.tgz", - "integrity": "sha512-T8oc1MbF8L+Bk2msAvCUzjxVB2Z2f+vXYfcucE2wOmYs7ZUwco5Ep0fYZw8quNwOiw9K8GYVL+Kgc2pETNTLOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.22.0", - "@typescript-eslint/types": "8.22.0", - "@typescript-eslint/typescript-estree": "8.22.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.22.0.tgz", - "integrity": "sha512-AWpYAXnUgvLNabGTy3uBylkgZoosva/miNd1I8Bz3SjotmQPbVqhO4Cczo8AsZ44XVErEBPr/CRSgaj8sG7g0w==", + "node_modules/@vue/shared": { + "version": "3.5.22", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.22.tgz", + "integrity": "sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w==", "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.22.0", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } + "license": "MIT" }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", "bin": { @@ -2106,19 +2410,55 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/alien-signals": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-0.4.14.tgz", + "integrity": "sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==", + "dev": true, + "license": "MIT" + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -2135,6 +2475,20 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -2142,24 +2496,14 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/aria-query": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", - "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/axobject-query": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", - "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=12" } }, "node_modules/balanced-match": { @@ -2170,18 +2514,31 @@ "license": "MIT" }, "node_modules/bignumber.js": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", - "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", "license": "MIT", "engines": { "node": "*" } }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -2212,6 +2569,16 @@ "node": ">=6" } }, + "node_modules/chai": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.1.tgz", + "integrity": "sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -2229,135 +2596,42 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, "license": "MIT", "dependencies": { - "readdirp": "^4.0.1" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" }, "engines": { - "node": ">= 14.16.0" + "node": ">= 8.10.0" }, "funding": { "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" }, - "engines": { - "node": ">=8" + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "is-glob": "^4.0.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/code-red": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", - "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15", - "@types/estree": "^1.0.1", - "acorn": "^8.10.0", - "estree-walker": "^3.0.3", - "periscopic": "^3.1.0" + "node": ">= 6" } }, "node_modules/color-convert": { @@ -2380,41 +2654,10 @@ "dev": true, "license": "MIT" }, - "node_modules/color-parse": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/color-parse/-/color-parse-2.0.2.tgz", - "integrity": "sha512-eCtOz5w5ttWIUcaKLiktF+DxZO1R9KLNY/xhbV6CkhM7sR3GhVghmt6X6yOnzeaM24po+Z9/S1apbXMwA3Iepw==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "^2.0.0" - } - }, - "node_modules/color-parse/node_modules/color-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.0.0.tgz", - "integrity": "sha512-SbtvAMWvASO5TE2QP07jHBMXKafgdZz8Vrsrn96fiL+O92/FN/PLARzUW5sKt013fjAprK2d2iCn2hk2Xb5oow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.20" - } - }, - "node_modules/color-rgba": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/color-rgba/-/color-rgba-3.0.0.tgz", - "integrity": "sha512-PPwZYkEY3M2THEHHV6Y95sGUie77S7X8v+h1r6LSAPF3/LL2xJ8duUXSrkic31Nzc4odPwHgUbiX/XuTYzQHQg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-parse": "^2.0.0", - "color-space": "^2.0.0" - } - }, - "node_modules/color-space": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/color-space/-/color-space-2.1.1.tgz", - "integrity": "sha512-XbeoH4Zpc20jdDau6NOyJ0uVMsKgAGn6dLR+qS2i9wu5U5pvI1InK34r4ODCS3Gmm2Wjmz20nTfhwqED7rY8AQ==", + "node_modules/compare-versions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", "dev": true, "license": "MIT" }, @@ -2425,31 +2668,12 @@ "dev": true, "license": "MIT" }, - "node_modules/concurrently": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.1.2.tgz", - "integrity": "sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.2", - "lodash": "^4.17.21", - "rxjs": "^7.8.1", - "shell-quote": "^1.8.1", - "supports-color": "^8.1.1", - "tree-kill": "^1.2.2", - "yargs": "^17.7.2" - }, - "bin": { - "conc": "dist/bin/concurrently.js", - "concurrently": "dist/bin/concurrently.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" - } + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "dev": true, + "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.6", @@ -2466,44 +2690,24 @@ "node": ">= 8" } }, - "node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dev": true, - "license": "MIT", - "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "dev": true, - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } + "license": "MIT" }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", "dev": true, "license": "MIT" }, "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "license": "MIT", "dependencies": { @@ -2518,13 +2722,6 @@ } } }, - "node_modules/dedent-js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dedent-js/-/dedent-js-1.0.1.tgz", - "integrity": "sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ==", - "dev": true, - "license": "MIT" - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -2532,34 +2729,10 @@ "dev": true, "license": "MIT" }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/dotenv": { - "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -2570,23 +2743,36 @@ } }, "node_modules/earcut": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.1.tgz", - "integrity": "sha512-0l1/0gOjESMeQyYaK5IDiPNvFeu93Z/cO0TjZh9eZ1vyCtZnA7KMZ8rQggpsJHIbGSdrqYq9OhuveadOVHCshw==", - "dev": true, + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.2.tgz", + "integrity": "sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==", + "devOptional": true, "license": "ISC" }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", "dev": true, "license": "MIT" }, "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz", + "integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -2594,42 +2780,35 @@ "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" + "@esbuild/aix-ppc64": "0.25.11", + "@esbuild/android-arm": "0.25.11", + "@esbuild/android-arm64": "0.25.11", + "@esbuild/android-x64": "0.25.11", + "@esbuild/darwin-arm64": "0.25.11", + "@esbuild/darwin-x64": "0.25.11", + "@esbuild/freebsd-arm64": "0.25.11", + "@esbuild/freebsd-x64": "0.25.11", + "@esbuild/linux-arm": "0.25.11", + "@esbuild/linux-arm64": "0.25.11", + "@esbuild/linux-ia32": "0.25.11", + "@esbuild/linux-loong64": "0.25.11", + "@esbuild/linux-mips64el": "0.25.11", + "@esbuild/linux-ppc64": "0.25.11", + "@esbuild/linux-riscv64": "0.25.11", + "@esbuild/linux-s390x": "0.25.11", + "@esbuild/linux-x64": "0.25.11", + "@esbuild/netbsd-arm64": "0.25.11", + "@esbuild/netbsd-x64": "0.25.11", + "@esbuild/openbsd-arm64": "0.25.11", + "@esbuild/openbsd-x64": "0.25.11", + "@esbuild/openharmony-arm64": "0.25.11", + "@esbuild/sunos-x64": "0.25.11", + "@esbuild/win32-arm64": "0.25.11", + "@esbuild/win32-ia32": "0.25.11", + "@esbuild/win32-x64": "0.25.11" } }, "node_modules/escape-string-regexp": { @@ -2646,32 +2825,32 @@ } }, "node_modules/eslint": { - "version": "9.19.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.19.0.tgz", - "integrity": "sha512-ug92j0LepKlbbEv6hD911THhoRHmbdXt2gX+VDABAW/Ir7D3nqKdv5Pf5vtlyY6HQMTEP2skXY43ueqTCWssEA==", + "version": "9.38.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.38.0.tgz", + "integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.19.0", - "@eslint/core": "^0.10.0", - "@eslint/eslintrc": "^3.2.0", - "@eslint/js": "9.19.0", - "@eslint/plugin-kit": "^0.2.5", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.1", + "@eslint/core": "^0.16.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.38.0", + "@eslint/plugin-kit": "^0.4.0", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.1", + "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.2.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -2705,61 +2884,57 @@ } } }, - "node_modules/eslint-compat-utils": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", - "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", - "dependencies": { - "semver": "^7.5.4" + "bin": { + "eslint-config-prettier": "bin/cli.js" }, - "engines": { - "node": ">=12" + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" }, "peerDependencies": { - "eslint": ">=6.0.0" + "eslint": ">=7.0.0" } }, - "node_modules/eslint-plugin-svelte": { - "version": "2.46.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-2.46.1.tgz", - "integrity": "sha512-7xYr2o4NID/f9OEYMqxsEQsCsj4KaMy4q5sANaKkAb6/QeCjYFxRmDm2S3YC3A3pl1kyPZ/syOx/i7LcWYSbIw==", + "node_modules/eslint-plugin-prettier": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz", + "integrity": "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@jridgewell/sourcemap-codec": "^1.4.15", - "eslint-compat-utils": "^0.5.1", - "esutils": "^2.0.3", - "known-css-properties": "^0.35.0", - "postcss": "^8.4.38", - "postcss-load-config": "^3.1.4", - "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.1.0", - "semver": "^7.6.2", - "svelte-eslint-parser": "^0.43.0" + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.11.7" }, "engines": { - "node": "^14.17.0 || >=16.0.0" + "node": "^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ota-meshi" + "url": "https://opencollective.com/eslint-plugin-prettier" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0-0 || ^9.0.0-0", - "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", + "prettier": ">=3.0.0" }, "peerDependenciesMeta": { - "svelte": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { "optional": true } } }, "node_modules/eslint-scope": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", - "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -2774,9 +2949,9 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -2786,23 +2961,29 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/esm-env": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", - "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", + "node_modules/eslint/node_modules/@eslint/core": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.16.0.tgz", + "integrity": "sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==", "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } }, "node_modules/espree": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.14.0", + "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" + "eslint-visitor-keys": "^4.2.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2848,14 +3029,11 @@ } }, "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } + "license": "MIT" }, "node_modules/esutils": { "version": "2.0.3", @@ -2877,6 +3055,23 @@ "node": ">=0.8.x" } }, + "node_modules/expect-type": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", + "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/exsolve": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", + "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2884,6 +3079,13 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", @@ -2928,10 +3130,27 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fastq": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz", - "integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", "dev": true, "license": "ISC", "dependencies": { @@ -2996,27 +3215,25 @@ } }, "node_modules/flatted": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", - "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true, "license": "ISC" }, - "node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "node_modules/fs-extra": { + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz", + "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=14.14" } }, "node_modules/fsevents": { @@ -3034,6 +3251,16 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/geo-coordinates-parser": { "version": "1.7.4", "resolved": "https://registry.npmjs.org/geo-coordinates-parser/-/geo-coordinates-parser-1.7.4.tgz", @@ -3044,7 +3271,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-4.0.2.tgz", "integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/geotiff": { @@ -3080,44 +3307,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "devOptional": true, + "license": "MIT", "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/gl-matrix": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", - "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==", - "dev": true, + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.4.tgz", + "integrity": "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==", + "devOptional": true, "license": "MIT" }, - "node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -3131,90 +3340,62 @@ "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/global-prefix": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-4.0.0.tgz", - "integrity": "sha512-w0Uf9Y9/nyHinEk5vMJKRie+wa4kR5hmDbEhGGds/kG1PwGLLHKRoNMeJOyCQjjBkANlnScqgzcFwGHgmgLkVA==", + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true, - "license": "MIT", - "dependencies": { - "ini": "^4.1.3", - "kind-of": "^6.0.3", - "which": "^4.0.0" - }, - "engines": { - "node": ">=16" - } + "license": "ISC" }, - "node_modules/global-prefix/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true, - "license": "ISC", - "engines": { - "node": ">=16" - } + "license": "MIT" }, - "node_modules/global-prefix/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "node_modules/happy-dom": { + "version": "20.0.10", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-20.0.10.tgz", + "integrity": "sha512-6umCCHcjQrhP5oXhrHQQvLB0bwb1UzHAHdsXy+FjtKoYjUhmNZsQL8NivwM1vDvNEChJabVrUYxUnp/ZdYmy2g==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" + "@types/node": "^20.0.0", + "@types/whatwg-mimetype": "^3.0.2", + "whatwg-mimetype": "^3.0.0" }, "engines": { - "node": "^16.13.0 || >=18.0.0" + "node": ">=20.0.0" } }, - "node_modules/globals": { - "version": "15.14.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz", - "integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==", + "node_modules/happy-dom/node_modules/@types/node": { + "version": "20.19.25", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.25.tgz", + "integrity": "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dependencies": { + "undici-types": "~6.21.0" } }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "node_modules/happy-dom/node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, "license": "MIT" }, @@ -3228,6 +3409,29 @@ "node": ">=8" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, "node_modules/husky": { "version": "9.1.7", "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", @@ -3244,27 +3448,6 @@ "url": "https://github.com/sponsors/typicode" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -3275,17 +3458,10 @@ "node": ">= 4" } }, - "node_modules/immutable": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.3.tgz", - "integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==", - "dev": true, - "license": "MIT" - }, "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3299,6 +3475,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -3306,17 +3492,36 @@ "dev": true, "license": "MIT", "engines": { - "node": ">=0.8.19" + "node": ">=0.8.19" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/ini": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", - "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, - "license": "ISC", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-extglob": { @@ -3352,16 +3557,6 @@ "node": ">=0.12.0" } }, - "node_modules/is-reference": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", - "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.6" - } - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3369,26 +3564,17 @@ "dev": true, "license": "ISC" }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } + "license": "MIT" }, "node_modules/js-base64": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.7.tgz", - "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==", + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.8.tgz", + "integrity": "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==", "dev": true, "license": "BSD-3-Clause" }, @@ -3430,14 +3616,27 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz", "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==", - "dev": true, + "devOptional": true, "license": "MIT" }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/kdbush": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz", "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/keyv": { @@ -3450,30 +3649,10 @@ "json-buffer": "3.0.1" } }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/kleur": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/known-css-properties": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.35.0.tgz", - "integrity": "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==", + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", "dev": true, "license": "MIT" }, @@ -3484,6 +3663,14 @@ "dev": true, "license": "BSD-2-Clause" }, + "node_modules/leaflet-v2": { + "name": "leaflet", + "version": "2.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-2.0.0-alpha.1.tgz", + "integrity": "sha512-2EJU27z/wljOgQCyybRkfrm5Xc3uy6huKehh0UAPsrAdwnSMxaplsqCl9cXPAuDm6D7uL6PCznYMDVIsaAdSdA==", + "dev": true, + "license": "BSD-2-Clause" + }, "node_modules/lerc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lerc/-/lerc-3.0.0.tgz", @@ -3505,12 +3692,54 @@ "node": ">= 0.8.0" } }, - "node_modules/locate-character": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", - "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "node_modules/lit": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.3.1.tgz", + "integrity": "sha512-Ksr/8L3PTapbdXJCk+EJVB78jDodUMaP54gD24W186zGRARvwrsPfS60wae/SSCTCNZVPd1chXqio1qHQmu4NA==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit/reactive-element": "^2.1.0", + "lit-element": "^4.2.0", + "lit-html": "^3.3.0" + } + }, + "node_modules/lit-element": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.2.1.tgz", + "integrity": "sha512-WGAWRGzirAgyphK2urmYOV72tlvnxw7YfyLDgQ+OZnM9vQQBQnumQ7jUJe6unEzwGU3ahFOjuz1iz1jjrpCPuw==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.4.0", + "@lit/reactive-element": "^2.1.0", + "lit-html": "^3.3.0" + } + }, + "node_modules/lit-html": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.1.tgz", + "integrity": "sha512-S9hbyDu/vs1qNrithiNyeyv64c9yqiW9l+DBgI18fL+MTvOtWoFR0FWiyq1TxaYef5wNlpEmzlXoBlZEO+WjoA==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, + "node_modules/local-pkg": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", + "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.3.0", + "quansync": "^0.2.11" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } }, "node_modules/locate-path": { "version": "6.0.0", @@ -3542,66 +3771,58 @@ "dev": true, "license": "MIT" }, - "node_modules/lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "tslib": "^2.0.3" + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, "node_modules/magic-string": { - "version": "0.30.17", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", - "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, "node_modules/maplibre-gl": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-5.1.0.tgz", - "integrity": "sha512-6lbf7qAnqAVm1T/vJBMmRtP+g8G/O/Z52IBtWX31SbFj7sEdlrk4YugxJen8IdV/pFjLFnDOw7HiHZl5nYdVjg==", - "dev": true, + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-5.6.2.tgz", + "integrity": "sha512-SEqYThhUCFf6Lm0TckpgpKnto5u4JsdPYdFJb6g12VtuaFsm3nYdBO+fOmnUYddc8dXihgoGnuXvPPooUcRv5w==", + "devOptional": true, "license": "BSD-3-Clause", "dependencies": { "@mapbox/geojson-rewind": "^0.5.2", "@mapbox/jsonlint-lines-primitives": "^2.0.2", - "@mapbox/point-geometry": "^0.1.0", - "@mapbox/tiny-sdf": "^2.0.6", + "@mapbox/point-geometry": "^1.1.0", + "@mapbox/tiny-sdf": "^2.0.7", "@mapbox/unitbezier": "^0.0.1", - "@mapbox/vector-tile": "^1.3.1", + "@mapbox/vector-tile": "^2.0.4", "@mapbox/whoots-js": "^3.1.0", - "@maplibre/maplibre-gl-style-spec": "^23.1.0", + "@maplibre/maplibre-gl-style-spec": "^23.3.0", + "@maplibre/vt-pbf": "^4.0.3", "@types/geojson": "^7946.0.16", "@types/geojson-vt": "3.2.5", - "@types/mapbox__point-geometry": "^0.1.4", - "@types/mapbox__vector-tile": "^1.3.4", - "@types/pbf": "^3.0.5", "@types/supercluster": "^7.1.3", - "earcut": "^3.0.1", + "earcut": "^3.0.2", "geojson-vt": "^4.0.2", "gl-matrix": "^3.4.3", - "global-prefix": "^4.0.0", "kdbush": "^4.0.2", "murmurhash-js": "^1.0.0", - "pbf": "^3.3.0", - "potpack": "^2.0.0", + "pbf": "^4.0.1", + "potpack": "^2.1.0", "quickselect": "^3.0.0", "supercluster": "^8.0.1", - "tinyqueue": "^3.0.0", - "vt-pbf": "^3.1.3" + "tinyqueue": "^3.0.0" }, "engines": { "node": ">=16.14.0", @@ -3611,13 +3832,6 @@ "url": "https://github.com/maplibre/maplibre-gl-js?sponsor=1" } }, - "node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true, - "license": "CC0-1.0" - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -3659,30 +3873,42 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, + "devOptional": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "node_modules/mlly": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", + "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" + "license": "MIT", + "dependencies": { + "acorn": "^8.15.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.1" } }, - "node_modules/mri": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", - "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "node_modules/mlly/node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/mlly/node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=4" + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" } }, "node_modules/ms": { @@ -3692,17 +3918,24 @@ "dev": true, "license": "MIT" }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true, + "license": "MIT" + }, "node_modules/murmurhash-js": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/murmurhash-js/-/murmurhash-js-1.0.0.tgz", "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, "funding": [ { @@ -3725,35 +3958,24 @@ "dev": true, "license": "MIT" }, - "node_modules/no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, "license": "MIT", - "dependencies": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/node-addon-api": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "dev": true, - "license": "MIT", - "optional": true - }, "node_modules/ol": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/ol/-/ol-10.4.0.tgz", - "integrity": "sha512-gv3voS4wgej1WVvdCz2ZIBq3lPWy8agaf0094E79piz8IGQzHiOWPs2in1pdoPmuTNvcqGqyUFG3IbxNE6n08g==", + "version": "10.6.1", + "resolved": "https://registry.npmjs.org/ol/-/ol-10.6.1.tgz", + "integrity": "sha512-xp174YOwPeLj7c7/8TCIEHQ4d41tgTDDhdv6SqNdySsql5/MaFJEJkjlsYcvOPt7xA6vrum/QG4UdJ0iCGT1cg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { "@types/rbush": "4.0.0", - "color-rgba": "^3.0.0", - "color-space": "^2.0.1", "earcut": "^3.0.0", "geotiff": "^2.1.3", "pbf": "4.0.1", @@ -3764,19 +3986,6 @@ "url": "https://opencollective.com/openlayers" } }, - "node_modules/ol/node_modules/pbf": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pbf/-/pbf-4.0.1.tgz", - "integrity": "sha512-SuLdBvS42z33m8ejRbInMapQe8n0D3vN/Xd5fmWM3tufNgRQFBpaW2YVJxQZV4iPNqb0vEFvssMEo5w9c6BTIA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "resolve-protobuf-schema": "^2.1.0" - }, - "bin": { - "pbf": "bin/pbf" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -3827,12 +4036,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "node_modules/p-map": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", "dev": true, - "license": "BlueOak-1.0.0" + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/pako": { "version": "2.1.0", @@ -3855,22 +4070,18 @@ } }, "node_modules/parse-headers": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", - "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.6.tgz", + "integrity": "sha512-Tz11t3uKztEW5FEVZnj1ox8GKblWn+PvHY9TmJV5Mll2uHEwRdR/5Li1OlXoECjLYkApdhWy44ocONwXLiKO5A==", "dev": true, "license": "MIT" }, - "node_modules/pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", "dev": true, - "license": "MIT", - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } + "license": "MIT" }, "node_modules/path-exists": { "version": "4.0.0", @@ -3892,49 +4103,33 @@ "node": ">=8" } }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } + "license": "MIT" }, - "node_modules/pbf": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.3.0.tgz", - "integrity": "sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==", + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, + "license": "MIT" + }, + "node_modules/pbf": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pbf/-/pbf-4.0.1.tgz", + "integrity": "sha512-SuLdBvS42z33m8ejRbInMapQe8n0D3vN/Xd5fmWM3tufNgRQFBpaW2YVJxQZV4iPNqb0vEFvssMEo5w9c6BTIA==", + "devOptional": true, "license": "BSD-3-Clause", "dependencies": { - "ieee754": "^1.1.12", "resolve-protobuf-schema": "^2.1.0" }, "bin": { "pbf": "bin/pbf" } }, - "node_modules/periscopic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", - "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^3.0.0", - "is-reference": "^3.0.0" - } - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -3955,6 +4150,18 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, "node_modules/polyclip-ts": { "version": "0.16.8", "resolved": "https://registry.npmjs.org/polyclip-ts/-/polyclip-ts-0.16.8.tgz", @@ -3966,9 +4173,9 @@ } }, "node_modules/postcss": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz", - "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==", + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dev": true, "funding": [ { @@ -3979,134 +4186,26 @@ "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.8", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-load-config": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", - "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", - "dev": true, - "license": "MIT", - "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^1.10.2" - }, - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/postcss-load-config/node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/postcss-load-config/node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 6" - } - }, - "node_modules/postcss-safe-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", - "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.3.3" - } - }, - "node_modules/postcss-scss": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz", - "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss-scss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "engines": { - "node": ">=12.0" - }, - "peerDependencies": { - "postcss": "^8.4.29" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { - "node": ">=4" + "node": "^10 || ^12 || >=14" } }, "node_modules/potpack": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.0.0.tgz", - "integrity": "sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==", - "dev": true, + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.1.0.tgz", + "integrity": "sha512-pcaShQc1Shq0y+E7GqJqvZj8DTthWV1KeHGdi0Z6IAin2Oi3JnLCOfwnCo84qc+HAp52wT9nK9H7FAJp5a44GQ==", + "devOptional": true, "license": "ISC" }, "node_modules/prelude-ls": { @@ -4120,9 +4219,9 @@ } }, "node_modules/prettier": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", - "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "license": "MIT", "bin": { @@ -4135,16 +4234,29 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/prettier-plugin-organize-imports": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.1.0.tgz", - "integrity": "sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.3.0.tgz", + "integrity": "sha512-FxFz0qFhyBsGdIsb697f/EkvHzi5SZOhWAjxcx2dLt+Q532bAlhswcXGYB1yzjZ69kW8UoadFBw7TyNwlq96Iw==", "dev": true, "license": "MIT", "peerDependencies": { "prettier": ">=2.0", "typescript": ">=2.9", - "vue-tsc": "^2.1.0" + "vue-tsc": "^2.1.0 || 3" }, "peerDependenciesMeta": { "vue-tsc": { @@ -4152,22 +4264,11 @@ } } }, - "node_modules/prettier-plugin-svelte": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.3.3.tgz", - "integrity": "sha512-yViK9zqQ+H2qZD1w/bH7W8i+bVfKrD8GIFjkFe4Thl6kCT9SlAsXVNmt3jCvQOCsnOhcvYgsoVlRV/Eu6x5nNw==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "prettier": "^3.0.0", - "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" - } - }, "node_modules/protocol-buffers-schema": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/punycode": { @@ -4180,6 +4281,23 @@ "node": ">=6" } }, + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -4202,9 +4320,9 @@ "license": "MIT" }, "node_modules/quick-lru": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-7.0.0.tgz", - "integrity": "sha512-MX8gB7cVYTrYcFfAnfLlhRd0+Toyl8yX8uBx1MrX7K0jegiz9TumwOK27ldXrgDlHRdVi+MqU9Ssw6dr4BNreg==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-7.3.0.tgz", + "integrity": "sha512-k9lSsjl36EJdK7I06v7APZCbyGT2vMTsYSRX1Q2nbYmnkBqgUhRkAuzH08Ciotteu/PLJmIF2+tti7o3C/ts2g==", "dev": true, "license": "MIT", "engines": { @@ -4218,7 +4336,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz", "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/rbush": { @@ -4232,9 +4350,9 @@ } }, "node_modules/react": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", - "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", + "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "dev": true, "license": "MIT", "engines": { @@ -4242,71 +4360,60 @@ } }, "node_modules/react-dom": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz", - "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", + "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", "dev": true, "license": "MIT", "dependencies": { - "scheduler": "^0.25.0" + "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.0.0" + "react": "^19.2.0" } }, "node_modules/readdirp": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.1.tgz", - "integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/replace-in-file": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/replace-in-file/-/replace-in-file-8.3.0.tgz", - "integrity": "sha512-4VhddQiMCPIuypiwHDTM+XHjZoVu9h7ngBbSCnwGRcwdHwxltjt/m//Ep3GDwqaOx1fDSrKFQ+n7uo4uVcEz9Q==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^5.3.0", - "glob": "^10.4.2", - "yargs": "^17.7.2" - }, - "bin": { - "replace-in-file": "bin/cli.js" + "picomatch": "^2.2.1" }, "engines": { - "node": ">=18" + "node": ">=8.10.0" } }, - "node_modules/replace-in-file/node_modules/chalk": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", - "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true, "license": "MIT", "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=0.10.0" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "dev": true, "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/resolve-from": { @@ -4323,16 +4430,16 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "protocol-buffers-schema": "^3.3.1" } }, "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, "license": "MIT", "engines": { @@ -4341,13 +4448,13 @@ } }, "node_modules/rollup": { - "version": "4.32.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.32.1.tgz", - "integrity": "sha512-z+aeEsOeEa3mEbS1Tjl6sAZ8NE3+AalQz1RJGj81M+fizusbdDMoEJwdJNHfaB40Scr4qNu+welOfes7maKonA==", + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz", + "integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.6" + "@types/estree": "1.0.8" }, "bin": { "rollup": "dist/bin/rollup" @@ -4357,25 +4464,28 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.32.1", - "@rollup/rollup-android-arm64": "4.32.1", - "@rollup/rollup-darwin-arm64": "4.32.1", - "@rollup/rollup-darwin-x64": "4.32.1", - "@rollup/rollup-freebsd-arm64": "4.32.1", - "@rollup/rollup-freebsd-x64": "4.32.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.32.1", - "@rollup/rollup-linux-arm-musleabihf": "4.32.1", - "@rollup/rollup-linux-arm64-gnu": "4.32.1", - "@rollup/rollup-linux-arm64-musl": "4.32.1", - "@rollup/rollup-linux-loongarch64-gnu": "4.32.1", - "@rollup/rollup-linux-powerpc64le-gnu": "4.32.1", - "@rollup/rollup-linux-riscv64-gnu": "4.32.1", - "@rollup/rollup-linux-s390x-gnu": "4.32.1", - "@rollup/rollup-linux-x64-gnu": "4.32.1", - "@rollup/rollup-linux-x64-musl": "4.32.1", - "@rollup/rollup-win32-arm64-msvc": "4.32.1", - "@rollup/rollup-win32-ia32-msvc": "4.32.1", - "@rollup/rollup-win32-x64-msvc": "4.32.1", + "@rollup/rollup-android-arm-eabi": "4.52.5", + "@rollup/rollup-android-arm64": "4.52.5", + "@rollup/rollup-darwin-arm64": "4.52.5", + "@rollup/rollup-darwin-x64": "4.52.5", + "@rollup/rollup-freebsd-arm64": "4.52.5", + "@rollup/rollup-freebsd-x64": "4.52.5", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", + "@rollup/rollup-linux-arm-musleabihf": "4.52.5", + "@rollup/rollup-linux-arm64-gnu": "4.52.5", + "@rollup/rollup-linux-arm64-musl": "4.52.5", + "@rollup/rollup-linux-loong64-gnu": "4.52.5", + "@rollup/rollup-linux-ppc64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-musl": "4.52.5", + "@rollup/rollup-linux-s390x-gnu": "4.52.5", + "@rollup/rollup-linux-x64-gnu": "4.52.5", + "@rollup/rollup-linux-x64-musl": "4.52.5", + "@rollup/rollup-openharmony-arm64": "4.52.5", + "@rollup/rollup-win32-arm64-msvc": "4.52.5", + "@rollup/rollup-win32-ia32-msvc": "4.52.5", + "@rollup/rollup-win32-x64-gnu": "4.52.5", + "@rollup/rollup-win32-x64-msvc": "4.52.5", "fsevents": "~2.3.2" } }, @@ -4407,64 +4517,20 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause" }, - "node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/sade": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", - "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "mri": "^1.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/sass": { - "version": "1.83.4", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.83.4.tgz", - "integrity": "sha512-B1bozCeNQiOgDcLd33e2Cs2U60wZwjUUXzh900ZyQF5qUasvMdDZYbQ566LJu7cqR+sAHlAfO6RMkaID5s6qpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "chokidar": "^4.0.0", - "immutable": "^5.0.2", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" - }, - "engines": { - "node": ">=14.0.0" - }, - "optionalDependencies": { - "@parcel/watcher": "^2.4.1" - } - }, "node_modules/scheduler": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", - "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==", + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "dev": true, "license": "MIT" }, "node_modules/semver": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.0.tgz", - "integrity": "sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, "license": "ISC", "bin": { @@ -4497,30 +4563,21 @@ "node": ">=8" } }, - "node_modules/shell-quote": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", - "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "ISC" }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, - "license": "ISC", + "license": "BSD-3-Clause", "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=0.10.0" } }, "node_modules/source-map-js": { @@ -4539,100 +4596,35 @@ "integrity": "sha512-0kGecIZNIReCSiznK3uheYB8sbstLjCZLiwcQwbmLhgHJj2gz6OnSPkVzJQCMnmEz1BQ4gPK59ylhBoEWOhGNA==", "license": "BDS-3-Clause" }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "BSD-3-Clause" }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", "dev": true, "license": "MIT" }, - "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.6.19" } }, "node_modules/strip-json-comments": { @@ -4652,275 +4644,133 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz", "integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "kdbush": "^4.0.2" } }, "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/svelte": { - "version": "4.2.19", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.19.tgz", - "integrity": "sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.1", - "@jridgewell/sourcemap-codec": "^1.4.15", - "@jridgewell/trace-mapping": "^0.3.18", - "@types/estree": "^1.0.1", - "acorn": "^8.9.0", - "aria-query": "^5.3.0", - "axobject-query": "^4.0.0", - "code-red": "^1.0.3", - "css-tree": "^2.3.1", - "estree-walker": "^3.0.3", - "is-reference": "^3.0.1", - "locate-character": "^3.0.0", - "magic-string": "^0.30.4", - "periscopic": "^3.1.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/svelte-check": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.1.4.tgz", - "integrity": "sha512-v0j7yLbT29MezzaQJPEDwksybTE2Ups9rUxEXy92T06TiA0cbqcO8wAOwNUVkFW6B0hsYHA+oAX3BS8b/2oHtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", - "chokidar": "^4.0.1", - "fdir": "^6.2.0", - "picocolors": "^1.0.0", - "sade": "^1.7.4" - }, - "bin": { - "svelte-check": "bin/svelte-check" - }, - "engines": { - "node": ">= 18.0.0" - }, - "peerDependencies": { - "svelte": "^4.0.0 || ^5.0.0-next.0", - "typescript": ">=5.0.0" - } - }, - "node_modules/svelte-check/node_modules/fdir": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", - "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/svelte-check/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "node": ">=8" } }, - "node_modules/svelte-eslint-parser": { - "version": "0.43.0", - "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.43.0.tgz", - "integrity": "sha512-GpU52uPKKcVnh8tKN5P4UZpJ/fUDndmq7wfsvoVXsyP+aY0anol7Yqo01fyrlaWGMFfm4av5DyrjlaXdLRJvGA==", + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, "license": "MIT", - "dependencies": { - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "postcss": "^8.4.39", - "postcss-scss": "^4.0.9" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ota-meshi" - }, - "peerDependencies": { - "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "svelte": { - "optional": true - } - } - }, - "node_modules/svelte-eslint-parser/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/svelte-eslint-parser/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 0.4" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/svelte-eslint-parser/node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "node_modules/synckit": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", + "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "@pkgr/core": "^0.2.9" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://opencollective.com/synckit" } }, - "node_modules/svelte-hmr": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.16.0.tgz", - "integrity": "sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA==", + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", "dev": true, - "license": "ISC", + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, "engines": { - "node": "^12.20 || ^14.13.1 || >= 16" + "node": ">=12.0.0" }, - "peerDependencies": { - "svelte": "^3.19.0 || ^4.0.0" + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/svelte-preprocess": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-6.0.3.tgz", - "integrity": "sha512-PLG2k05qHdhmRG7zR/dyo5qKvakhm8IJ+hD2eFRQmMLHp7X3eJnjeupUtvuRpbNiF31RjVw45W+abDwHEmP5OA==", + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, - "hasInstallScript": true, "license": "MIT", "engines": { - "node": ">= 18.0.0" + "node": ">=12.0.0" }, "peerDependencies": { - "@babel/core": "^7.10.2", - "coffeescript": "^2.5.1", - "less": "^3.11.3 || ^4.0.0", - "postcss": "^7 || ^8", - "postcss-load-config": ">=3", - "pug": "^3.0.0", - "sass": "^1.26.8", - "stylus": ">=0.55", - "sugarss": "^2.0.0 || ^3.0.0 || ^4.0.0", - "svelte": "^4.0.0 || ^5.0.0-next.100 || ^5.0.0", - "typescript": "^5.0.0" + "picomatch": "^3 || ^4" }, "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "coffeescript": { - "optional": true - }, - "less": { - "optional": true - }, - "postcss": { - "optional": true - }, - "postcss-load-config": { - "optional": true - }, - "pug": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "typescript": { + "picomatch": { "optional": true } } }, - "node_modules/svelte2tsx": { - "version": "0.7.34", - "resolved": "https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.7.34.tgz", - "integrity": "sha512-WTMhpNhFf8/h3SMtR5dkdSy2qfveomkhYei/QW9gSPccb0/b82tjHvLop6vT303ZkGswU/da1s6XvrLgthQPCw==", + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "dependencies": { - "dedent-js": "^1.0.1", - "pascal-case": "^3.1.1" + "engines": { + "node": ">=12" }, - "peerDependencies": { - "svelte": "^3.55 || ^4.0.0-next.0 || ^4.0 || ^5.0.0-next.0", - "typescript": "^4.9.4 || ^5.0.0" + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/tinyqueue": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==", - "dev": true, + "devOptional": true, "license": "ISC" }, + "node_modules/tinyrainbow": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", + "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -4934,20 +4784,10 @@ "node": ">=8.0" } }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "license": "MIT", - "bin": { - "tree-kill": "cli.js" - } - }, "node_modules/ts-api-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz", - "integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", "dev": true, "license": "MIT", "engines": { @@ -4977,9 +4817,9 @@ } }, "node_modules/typescript": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4991,15 +4831,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.22.0.tgz", - "integrity": "sha512-Y2rj210FW1Wb6TWXzQc5+P+EWI9/zdS57hLEc0gnyuvdzWo8+Y8brKlbj0muejonhMI/xAZCnZZwjbIfv1CkOw==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.46.2.tgz", + "integrity": "sha512-vbw8bOmiuYNdzzV3lsiWv6sRwjyuKJMQqWulBOU7M0RrxedXledX8G8kBbQeiOYDnTfiXz0Y4081E1QMNB6iQg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.22.0", - "@typescript-eslint/parser": "8.22.0", - "@typescript-eslint/utils": "8.22.0" + "@typescript-eslint/eslint-plugin": "8.46.2", + "@typescript-eslint/parser": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2", + "@typescript-eslint/utils": "8.46.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5010,16 +4851,33 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <6.0.0" } }, + "node_modules/ufo": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", + "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", + "dev": true, + "license": "MIT" + }, "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "dev": true, "license": "MIT" }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -5030,17 +4888,10 @@ "punycode": "^2.1.0" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, "node_modules/uuid": { - "version": "11.0.5", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.5.tgz", - "integrity": "sha512-508e6IcKLrhxKdBbcA2b4KQZlLVp2+J5UwQ6F7Drckkc5N9ZJwFa4TgWtsww9UG8fGHbm6gbV19TdM5pQ4GaIA==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", "dev": true, "funding": [ "https://github.com/sponsors/broofa", @@ -5052,21 +4903,24 @@ } }, "node_modules/vite": { - "version": "5.4.14", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz", - "integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==", + "version": "7.1.12", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.12.tgz", + "integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -5075,19 +4929,25 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, + "jiti": { + "optional": true + }, "less": { "optional": true }, @@ -5108,17 +4968,35 @@ }, "terser": { "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true } } }, - "node_modules/vitefu": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", - "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", + "node_modules/vite-plugin-dts": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/vite-plugin-dts/-/vite-plugin-dts-4.5.4.tgz", + "integrity": "sha512-d4sOM8M/8z7vRXHHq/ebbblfaxENjogAAekcfcDCCwAyvGqnPrc7f4NZbvItS+g4WTgerW0xDwSz5qz11JT3vg==", "dev": true, "license": "MIT", + "dependencies": { + "@microsoft/api-extractor": "^7.50.1", + "@rollup/pluginutils": "^5.1.4", + "@volar/typescript": "^2.4.11", + "@vue/language-core": "2.2.0", + "compare-versions": "^6.1.1", + "debug": "^4.4.0", + "kolorist": "^1.8.0", + "local-pkg": "^1.0.0", + "magic-string": "^0.30.17" + }, "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + "typescript": "*", + "vite": "*" }, "peerDependenciesMeta": { "vite": { @@ -5126,225 +5004,240 @@ } } }, - "node_modules/vt-pbf": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/vt-pbf/-/vt-pbf-3.1.3.tgz", - "integrity": "sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==", + "node_modules/vite-plugin-externalize-deps": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/vite-plugin-externalize-deps/-/vite-plugin-externalize-deps-0.10.0.tgz", + "integrity": "sha512-eQrtpT/Do7AvDn76l1yL6ZHyXJ+UWH2LaHVqhAes9go54qaAnPZuMbgxcroQ/7WY3ZyetZzYW2quQnDF0DV5qg==", "dev": true, "license": "MIT", - "dependencies": { - "@mapbox/point-geometry": "0.1.0", - "@mapbox/vector-tile": "^1.3.1", - "pbf": "^3.2.1" - } - }, - "node_modules/web-worker": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.3.0.tgz", - "integrity": "sha512-BSR9wyRsy/KOValMgd5kMyr3JzpdeoR9KVId8u5GVlTTAtNChlsE4yTxeY7zMdNSyOmoKBv8NH2qeRY9Tg+IaA==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "funding": { + "url": "https://github.com/sponsors/voracious" }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "peerDependencies": { + "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/vite-plugin-static-copy": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-3.1.4.tgz", + "integrity": "sha512-iCmr4GSw4eSnaB+G8zc2f4dxSuDjbkjwpuBLLGvQYR9IW7rnDzftnUjOH5p4RYR+d4GsiBqXRvzuFhs5bnzVyw==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "chokidar": "^3.6.0", + "p-map": "^7.0.3", + "picocolors": "^1.1.1", + "tinyglobby": "^0.2.15" }, "engines": { - "node": ">=10" + "node": "^18.0.0 || >=20.0.0" }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "node_modules/vitest": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.9.tgz", + "integrity": "sha512-E0Ja2AX4th+CG33yAFRC+d1wFx2pzU5r6HtG6LiPSE04flaE0qB6YyjSw9ZcpJAtVPfsvZGtJlKWZpuW7EHRxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.0.9", + "@vitest/mocker": "4.0.9", + "@vitest/pretty-format": "4.0.9", + "@vitest/runner": "4.0.9", + "@vitest/snapshot": "4.0.9", + "@vitest/spy": "4.0.9", + "@vitest/utils": "4.0.9", + "debug": "^4.4.3", + "es-module-lexer": "^1.7.0", + "expect-type": "^1.2.2", + "magic-string": "^0.30.21", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^3.10.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" }, "engines": { - "node": ">=8" + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.0.9", + "@vitest/browser-preview": "4.0.9", + "@vitest/browser-webdriverio": "4.0.9", + "@vitest/ui": "4.0.9", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } } }, - "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/xml-utils": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/xml-utils/-/xml-utils-1.10.1.tgz", - "integrity": "sha512-Dn6vJ1Z9v1tepSjvnCpwk5QqwIPcEFKdgnjqfYOABv1ngSofuAhtlugcUC3ehS1OHdgDWSG6C5mvj+Qm15udTQ==", + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", "dev": true, - "license": "CC0-1.0" + "license": "MIT" }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "node_modules/web-worker": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.5.0.tgz", + "integrity": "sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw==", "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } + "license": "Apache-2.0" }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", "dev": true, "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, "engines": { "node": ">=12" } }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, "engines": { - "node": ">=12" + "node": ">= 8" } }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, "engines": { "node": ">=8" } }, - "node_modules/yargs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/xml-utils": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/xml-utils/-/xml-utils-1.10.2.tgz", + "integrity": "sha512-RqM+2o1RYs6T8+3DzDSoTRAUfrvaejbVHcp3+thnAtDKo8LskR+HomLajEy5UjTz24rpka7AxVBRR3g2wTUkJA==", "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } + "license": "CC0-1.0" }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } + "license": "ISC" }, "node_modules/yocto-queue": { "version": "0.1.0", diff --git a/package.json b/package.json index c3fc804..f7ae8f5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@maptiler/geocoding-control", - "version": "2.1.7", + "version": "3.0.0", "description": "The Javascript & TypeScript Map Control component for MapTiler Geocoding service. Easy to be integrated into any JavaScript mapping application.", "type": "module", "author": { @@ -26,126 +26,91 @@ "search", "leaflet-control", "maplibre-control", - "control", - "react", - "svelte" + "control" ], "scripts": { - "dev": "vite --host", + "dev": "vite -c vite.config-dev.ts", "make": "npm run clean && npm run build", - "build": "node sync-info.js run && npm run check && concurrently --names \"SVELTE ,MAPLIBRE,MAPTILER,MAPLIB-C,LEAFLET ,LEAFLE-C,OL ,OL-C ,REACT ,TYPES ,VANILLA \" \"npm run build-svelte\" \"npm run build-maplibre\" \"npm run build-maptilersdk\" \"npm run build-maplibre-controller\" \"npm run build-leaflet\" \"npm run build-leaflet-controller\" \"npm run build-openlayers\" \"npm run build-openlayers-controller\" \"npm run build-react\" \"npm run build-vanilla\" \"npm run build-types\" && cp LICENSE README.md package.json dist && cp -r dist.svelte dist/svelte", - "build-svelte": "svelte-package -i src -o dist.svelte && VITE_LIB_VERSION=$npm_package_version node replace-env-vars.js", - "build-maptilersdk": "FLAVOUR=maptilersdk vite build", - "build-maplibre": "FLAVOUR=maplibre vite build", - "build-maplibre-controller": "FLAVOUR=maplibregl-controller vite build", - "build-leaflet": "FLAVOUR=leaflet vite build", - "build-leaflet-controller": "FLAVOUR=leaflet-controller vite build", - "build-openlayers": "FLAVOUR=openlayers vite build", - "build-openlayers-controller": "FLAVOUR=openlayers-controller vite build", - "build-react": "FLAVOUR=react vite build", - "build-vanilla": "FLAVOUR=vanilla vite build", - "build-types": "tsc --outDir dist --declaration --emitDeclarationOnly -p tsconfig.dist.json", + "build": "npm run build:index && npm run build:index:umd && npm run build:maptilersdk && npm run build:maptilersdk:umd && npm run build:maplibregl && npm run build:maplibregl:umd", + "build:index": "FLAVOUR=index vite build", + "build:index:umd": "FLAVOUR=index MODE=umd vite build", + "build:maptilersdk": "FLAVOUR=maptilersdk vite build", + "build:maptilersdk:umd": "FLAVOUR=maptilersdk MODE=umd vite build", + "build:maplibregl": "FLAVOUR=maplibregl vite build", + "build:maplibregl:umd": "FLAVOUR=maplibregl MODE=umd vite build", "lint": "eslint -c eslint.config.js . && prettier --check . && tsc --noEmit", "lint:fix": "eslint -c eslint.config.js --fix && prettier --write . && tsc --noEmit", - "clean": "rm -rf dist dist.svelte", - "pack": "npm run clean && npm run build && cd dist && npm pack", - "pub": "npm run clean && npm run build && cd dist && npm publish", - "pub-next": "npm run clean && npm run build && cd dist && npm publish --tag next", - "cdn-pr": "npm run clean && npm run build && ./create-cdn-pr.sh", + "test": "vitest run -c vite.config-test.ts --dom", + "test:watch": "vitest watch -c vite.config-test.ts --dom", + "clean": "rm -rf dist", "preview": "vite preview", - "check": "svelte-check --tsconfig ./tsconfig.json", "prepare": "husky" }, + "module": "dist/index.js", + "types": "dist/index.d.ts", + "main": "dist/index.js", "exports": { - "./leaflet": { - "import": "./leaflet.js", - "require": "./leaflet.umd.js" - }, - "./leaflet-controller": { - "import": "./leaflet-controller.js", - "require": "./leaflet-controller.umd.js" - }, - "./openlayers": { - "import": "./openlayers.js", - "require": "./openlayers.umd.js" - }, - "./openlayers-controller": { - "import": "./openlayers-controller.js", - "require": "./openlayers-controller.umd.js" + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.umd.js" }, "./maplibregl": { - "import": "./maplibregl.js", - "require": "./maplibregl.umd.js" + "types": "./dist/maplibregl.d.ts", + "import": "./dist/maplibregl.js", + "require": "./dist/maplibregl.umd.js" }, "./maptilersdk": { - "import": "./maptilersdk.js", - "require": "./maptilersdk.umd.js" - }, - "./maplibregl-controller": { - "import": "./maplibregl-controller.js", - "require": "./maplibregl-controller.umd.js" - }, - "./react": { - "import": "./react.js", - "require": "./react.umd.js" - }, - "./vanilla": { - "import": "./vanilla.js", - "require": "./vanilla.umd.js" - }, - "./style.css": { - "import": "./style.css", - "require": "./style.css" - }, - "./svelte/GeocodingControl.svelte": { - "types": "./svelte/GeocodingControl.svelte.d.ts", - "svelte": "./svelte/GeocodingControl.svelte" - }, - "./svelte/*": "./svelte/*", - "./types": "./types.d.ts" + "types": "./dist/maptilersdk.d.ts", + "import": "./dist/maptilersdk.js", + "require": "./dist/maptilersdk.umd.js" + } }, - "devDependencies": { - "@maptiler/sdk": "^3.0.1", - "@sveltejs/package": "^2.3.9", - "@sveltejs/vite-plugin-svelte": "^3.1.2", - "@tsconfig/svelte": "^5.0.4", + "dependencies": { + "@turf/bbox": "^7.2.0", + "@turf/difference": "^7.2.0", + "@turf/flatten": "^7.2.0", + "@turf/helpers": "^7.2.0", + "@turf/union": "^7.2.0", "@types/geojson": "^7946.0.16", - "@types/leaflet": "^1.9.16", - "@types/node": "^22.12.0", - "@types/react": "^19.0.8", - "@types/react-dom": "^19.0.3", - "concurrently": "^9.1.2", + "geo-coordinates-parser": "^1.7.4", + "lit": "^3.3.1" + }, + "devDependencies": { + "@canvas/image-data": "^1.1.0", + "@maptiler/sdk": "^3.8.0", + "@types/leaflet": "^1.9.21", + "@types/node": "ts5.8", + "@types/react": "^19.2.6", + "@types/react-dom": "^19.2.3", + "@vitest/web-worker": "^4.0.9", "dotenv": "^16.4.7", - "eslint": "^9.19.0", - "eslint-plugin-svelte": "^2.46.1", - "esm-env": "^1.2.2", - "globals": "^15.14.0", + "eslint": "^9.38.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.4", + "happy-dom": "^20.0.10", "husky": "^9.1.7", "leaflet": "^1.9.4", - "maplibre-gl": "^5.1.0", - "ol": "10.4", - "prettier": "^3.4.2", - "prettier-plugin-organize-imports": "^4.1.0", - "prettier-plugin-svelte": "^3.3.3", - "react": "^19.0.0", - "react-dom": "^19.0.0", - "replace-in-file": "^8.3.0", - "sass": "^1.83.4", - "svelte": "^4.2.19", - "svelte-check": "^4.1.4", - "svelte-preprocess": "^6.0.3", + "leaflet-v2": "npm:leaflet@2.0.0-alpha.1", + "ol": "^10.6.1", + "prettier": "^3.6.2", + "prettier-plugin-organize-imports": "^4.3.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", "tslib": "^2.8.1", - "typescript": "^5.7.3", - "typescript-eslint": "^8.22.0", - "vite": "^5.4.14" + "typescript": "~5.8.3", + "typescript-eslint": "^8.46.2", + "vite": "^7.1.12", + "vite-plugin-dts": "^4.5.4", + "vite-plugin-externalize-deps": "^0.10.0", + "vite-plugin-static-copy": "^3.1.4", + "vitest": "^4.0.8" }, "peerDependencies": { - "@maptiler/sdk": "^1 || ^2 || ^3", - "leaflet": "^1.7 || ^1.8 || ^1.9", - "maplibre-gl": "^2 || ^3 || ^4 || ^5", - "ol": "^6 || ^7 || ^8 || ^9 || ^10", - "react": "^17 || ^18 || ^19", - "svelte": "^4.2" + "@maptiler/sdk": "1 - 3", + "leaflet": "1.7 - 2", + "maplibre-gl": "2 - 5", + "ol": "6 - 10" }, "peerDependenciesMeta": { "@maptiler/sdk": { @@ -159,20 +124,6 @@ }, "ol": { "optional": true - }, - "react": { - "optional": true - }, - "svelte": { - "optional": true } - }, - "dependencies": { - "@turf/bbox": "^7.2.0", - "@turf/clone": "^7.2.0", - "@turf/difference": "^7.2.0", - "@turf/flatten": "^7.2.0", - "@turf/union": "^7.2.0", - "geo-coordinates-parser": "^1.7.4" } } diff --git a/replace-env-vars.js b/replace-env-vars.js deleted file mode 100644 index e57552f..0000000 --- a/replace-env-vars.js +++ /dev/null @@ -1,12 +0,0 @@ -import "dotenv/config"; -import { replaceInFile } from "replace-in-file"; - -replaceInFile({ - files: ["dist.svelte/*.svelte", "dist.svelte/*.ts", "dist.svelte/*.js"], - from: /\bimport\.meta\.env\.(\w+)/g, - to: (_, name) => JSON.stringify(process.env[name]), -}).catch((err) => { - console.error(err); - - process.exit(1); -}); diff --git a/src/ClearIcon.svelte b/src/ClearIcon.svelte deleted file mode 100644 index 6dd1621..0000000 --- a/src/ClearIcon.svelte +++ /dev/null @@ -1,12 +0,0 @@ - - - - - diff --git a/src/FailIcon.svelte b/src/FailIcon.svelte deleted file mode 100644 index 9904fed..0000000 --- a/src/FailIcon.svelte +++ /dev/null @@ -1,12 +0,0 @@ - - - - - diff --git a/src/FeatureItem.svelte b/src/FeatureItem.svelte deleted file mode 100644 index 8979353..0000000 --- a/src/FeatureItem.svelte +++ /dev/null @@ -1,296 +0,0 @@ - - - - - -
  • dispatch("select", undefined)} - on:click={(ev) => { - // this is to trigger the event if we click on focused item - if (document.activeElement !== ev.target) { - dispatch("select", undefined); - } - }} -> - {#if sprites && spriteIcon} -
    - {:else if imageUrl} - {category} handleImgError()} - /> - {:else if feature.address} - {placeType} - {:else if feature.id.startsWith("road.")} - {placeType} - {:else if feature.id.startsWith("address.")} - {placeType} - {:else if feature.id.startsWith("postal_code.")} - {placeType} - {:else if feature.id.startsWith("poi.")} - {placeType} - {:else if isReverse} - {placeType} - {:else} - {placeType} - {/if} - - - - - {isReverse ? feature.place_name : feature.place_name.replace(/,.*/, "")} - - - {#if showPlaceType === "always" || (showPlaceType !== "never" && !feature.address && !feature.id.startsWith("road.") && !feature.id.startsWith("address.") && !feature.id.startsWith("postal_code.") && (!feature.id.startsWith("poi.") || !imageUrl) && !isReverse)} - - {placeType} - - {/if} - - - - {isReverse ? "" : feature.place_name.replace(/[^,]*,?\s*/, "")} - - -
  • - - diff --git a/src/GeocodingControl.svelte b/src/GeocodingControl.svelte deleted file mode 100644 index 6f399e5..0000000 --- a/src/GeocodingControl.svelte +++ /dev/null @@ -1,1224 +0,0 @@ - - -{#if false} - - -{/if} - -
    -
    - - - (focused = true)} - on:blur={() => (focused = false)} - on:click={() => (focused = true)} - on:keydown={handleKeyDown} - on:input={handleInput} - on:change={() => (picked = undefined)} - {placeholder} - aria-label={placeholder} - /> - -
    - {#if !abortController} - - {/if} - - {#if abortController} - - {/if} -
    - - {#if enableReverse === "button"} - - {/if} - - -
    - - {#if error} -
    - - -
    {errorMessage}
    - - -
    - {:else if !focusedDelayed && !keepListOpen} - {""} - {:else if listFeatures?.length === 0} -
    - - -
    {noResultsMessage}
    -
    - {:else if listFeatures?.length && (focusedDelayed || keepListOpen)} -
      undefined} - on:keydown={handleKeyDown} - role="listbox" - > - {#each listFeatures as feature, i (feature.id + (feature.address ? "," + feature.address : ""))} - handleMouseEnter(i)} - on:select={() => pick(feature)} - {missingIconsCache} - {iconsBaseUrl} - /> - {/each} -
    - {/if} -
    - - diff --git a/src/LoadingIcon.svelte b/src/LoadingIcon.svelte deleted file mode 100644 index f553309..0000000 --- a/src/LoadingIcon.svelte +++ /dev/null @@ -1,40 +0,0 @@ -
    - - - - -
    - - diff --git a/src/MapLibreBasedGeocodingControl.ts b/src/MapLibreBasedGeocodingControl.ts deleted file mode 100644 index 55ec06c..0000000 --- a/src/MapLibreBasedGeocodingControl.ts +++ /dev/null @@ -1,471 +0,0 @@ -import type { - Evented, - FitBoundsOptions, - FlyToOptions, - Listener, - Map, - Marker, - MarkerOptions, - Subscription, -} from "maplibre-gl"; -import type { SvelteComponent } from "svelte"; -import GeocodingControlComponent from "./GeocodingControl.svelte"; -import { - createMapLibreGlMapController, - type FullGeometryStyle, - type MapLibreGL, -} from "./maplibregl-controller"; -import type { - ControlOptions, - DispatcherType, - DispatcherTypeCC, - Feature, - FeatureCollection, - RedefineType, -} from "./types"; -export { - createMapLibreGlMapController, - type MapLibreGL, -} from "./maplibregl-controller"; - -export type MapLibreBaseControlOptions = Omit & { - /** - * Marker to be added to the map at the location of the user-selected result using a default set of Marker options. - * - * - If `true` or `undefined` then a default marker will be used. - * - If the value is a [MarkerOptions](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/MarkerOptions/) then the marker will be constructed using these options. - * - If the value is a function then it can return instance of the [Marker](https://maplibre.org/maplibre-gl-js/docs/API/classes/Marker/). - * Function can accept `Feature` as a parameter which is `undefined` for the reverse location marker. - * - If `false` or `null` then no marker will be added to the map. - * - * Requires that `options.maplibregl` also be set. - * - * Default value is `true`. - */ - marker?: - | null - | boolean - | MarkerOptions - | ((map: Map, feature?: Feature) => undefined | null | Marker); - - /** - * Marker be added to the map at the location the geocoding results. - * - * - If `true` or `undefined` then a default marker will be used. - * - If the value is a [MarkerOptions](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/MarkerOptions/) then the marker will be constructed using these options. - * - If the value is a function then it can return instance of the [Marker](https://maplibre.org/maplibre-gl-js/docs/API/classes/Marker/). - * In this case the default pop-up won't be added to the marker. - * Function can accept `Feature` as a parameter. - * - If `false` or `null` then no marker will be added to the map. - * - * Requires that `options.maplibregl` also be set. - * - * Default value is `true`. - */ - showResultMarkers?: - | null - | boolean - | MarkerOptions - | ((map: Map, feature: Feature) => undefined | null | Marker); - - /** - * Animation to selected feature on the map. - * - * - If `false` or `null` then animating the map to a selected result is disabled. - * - If `true` or `undefined` then animating the map will use the default animation parameters. - * - If an [FlyToOptions](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/FlyToOptions/) - * ` & `[FitBoundsOptions](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/FitBoundsOptions/) - * then it will be passed as options to the map [flyTo](https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/#flyto) - * or [fitBounds](https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/#fitbounds) method providing control over the animation of the transition. - * - * Default value is `true`. - */ - flyTo?: null | boolean | (FlyToOptions & FitBoundsOptions); - - /** - * Style for full feature geometry GeoJSON. - * - * - If `false` or `null` then no full geometry is drawn. - * - If `true` or `undefined` then default-styled full geometry is drawn. - * - If an T then it must represent the style and will be used to style the full geometry. - * - * Default is the default style. - */ - fullGeometryStyle?: null | boolean | FullGeometryStyle; -}; - -export type Props = T extends SvelteComponent ? P : never; - -type RemoveString = T extends string ? never : T; - -type Event$1 = RemoveString[0]>; - -type EventedConstructor = new ( - ...args: ConstructorParameters -) => Evented; - -export function crateClasses( - Evented: EventedConstructor, - maplibreGl: MapLibreGL, - getExtraProps?: ( - map: Map, - div: HTMLElement, - ) => Partial>, -) { - type EventTypes = RedefineType< - DispatcherType, - { - select: SelectEvent; - featureslisted: FeaturesListedEvent; - featuresmarked: FeaturesMarkedEvent; - optionsvisibilitychange: OptionsVisibilityChangeEvent; - pick: PickEvent; - querychange: QueryChangeEvent; - response: ResponseEvent; - reversetoggle: ReverseToggleEvent; - } - >; - - // NOTE We can't use Maplibre `Event` - see https://github.com/maplibre/maplibre-gl-js/issues/5015 - class Event implements Event$1 { - readonly type: TYPE; - readonly target: MapLibreBasedGeocodingControl; - - constructor(target: MapLibreBasedGeocodingControl, type: TYPE) { - this.type = type; - this.target = target; - } - } - - class SelectEvent extends Event<"select"> { - feature: Feature | undefined; - - constructor( - target: MapLibreBasedGeocodingControl, - details: { feature: Feature | undefined }, - ) { - super(target, "select"); - - Object.assign(this, details); - } - } - - class FeaturesListedEvent extends Event<"featureslisted"> { - features: Feature[] | undefined; - - constructor( - target: MapLibreBasedGeocodingControl, - features: Feature[] | undefined, - ) { - super(target, "featureslisted"); - - this.features = features; - } - } - - class FeaturesMarkedEvent extends Event<"featuresmarked"> { - features: Feature[] | undefined; - - constructor( - target: MapLibreBasedGeocodingControl, - features: Feature[] | undefined, - ) { - super(target, "featuresmarked"); - - this.features = features; - } - } - - class OptionsVisibilityChangeEvent extends Event<"optionsvisibilitychange"> { - optionsVisible: boolean; - - constructor( - target: MapLibreBasedGeocodingControl, - optionsVisible: boolean, - ) { - super(target, "optionsvisibilitychange"); - - this.optionsVisible = optionsVisible; - } - } - - class PickEvent extends Event<"pick"> { - feature: Feature | undefined; - - constructor( - target: MapLibreBasedGeocodingControl, - feature: Feature | undefined, - ) { - super(target, "pick"); - - this.feature = feature; - } - } - - class QueryChangeEvent extends Event<"querychange"> { - query: string; - - constructor(target: MapLibreBasedGeocodingControl, query: string) { - super(target, "querychange"); - - this.query = query; - } - } - - class ResponseEvent extends Event<"response"> { - url: string; - - featureCollection: FeatureCollection; - - constructor( - target: MapLibreBasedGeocodingControl, - url: string, - featureCollection: FeatureCollection, - ) { - super(target, "response"); - - this.url = url; - - this.featureCollection = featureCollection; - } - } - - class ReverseToggleEvent extends Event<"reversetoggle"> { - reverse: boolean; - - constructor(target: MapLibreBasedGeocodingControl, reverse: boolean) { - super(target, "reversetoggle"); - - this.reverse = reverse; - } - } - - class MapLibreBasedGeocodingControl extends Evented { - #gc?: GeocodingControlComponent; - - #options: OPTS; - - #container?: HTMLElement; - - constructor(options: OPTS = {} as OPTS) { - super(); - - this.#options = options; - } - - onAddInt(map: Map): HTMLElement { - const div = document.createElement("div"); - - div.className = - "mapboxgl-ctrl-geocoder mapboxgl-ctrl maplibregl-ctrl-geocoder maplibregl-ctrl mapboxgl-ctrl-group"; - - const { - marker, - showResultMarkers, - flyTo, - fullGeometryStyle, - ...restOptions - } = this.#options; - - const flyToOptions = typeof flyTo === "boolean" ? {} : flyTo; - - const mapController = createMapLibreGlMapController( - map, - maplibreGl, - marker, - showResultMarkers, - flyToOptions, - flyToOptions, - fullGeometryStyle, - ); - - const props = { - mapController, - flyTo: flyTo === undefined ? true : !!flyTo, - apiKey: "", // just to satisfy apiKey; TODO find a better solution - ...getExtraProps?.(map, div), - ...restOptions, - }; - - if (!props.apiKey) { - console.warn( - "No MapTiler Cloud API key was provided, some or all geocoding requests may fail", - ); - } - - this.#gc = new GeocodingControlComponent({ target: div, props }); - - this.#gc.$on("select", (event) => { - this.fire(new SelectEvent(this, event.detail)); - }); - - this.#gc.$on("pick", (event) => { - this.fire(new PickEvent(this, event.detail.feature)); - }); - - this.#gc.$on("featureslisted", (event) => { - this.fire(new FeaturesListedEvent(this, event.detail.features)); - }); - - this.#gc.$on("featuresmarked", (event) => { - this.fire(new FeaturesMarkedEvent(this, event.detail.features)); - }); - - this.#gc.$on("response", (event) => { - this.fire( - new ResponseEvent( - this, - event.detail.url, - event.detail.featureCollection, - ), - ); - }); - - this.#gc.$on("optionsvisibilitychange", (event) => { - this.fire( - new OptionsVisibilityChangeEvent(this, event.detail.optionsVisible), - ); - }); - - this.#gc.$on("reversetoggle", (event) => { - this.fire(new ReverseToggleEvent(this, event.detail.reverse)); - }); - - this.#gc.$on("querychange", (event) => { - this.fire(new QueryChangeEvent(this, event.detail.query)); - }); - - this.#container = div; - - return div; - } - - on( - type: T, - listener: (ev: EventTypes[T]) => void, - ): Subscription; // TODO add backward type compatibility; in MapLibre v4 it returns `this`. - - on(type: keyof EventTypes, listener: Listener): Subscription { - return super.on(type, listener); - } - - once( - type: T, - listener?: (ev: EventTypes[T]) => void, - ): this | Promise; - - once(type: keyof EventTypes, listener?: Listener): this | Promise { - return super.once(type, listener); - } - - off( - type: T, - listener: (ev: EventTypes[T]) => void, - ): this; - - off(type: keyof EventTypes, listener: Listener): this { - return super.off(type, listener); - } - - listens(type: keyof EventTypes): boolean; - - listens(type: keyof EventTypes): boolean { - return super.listens(type); - } - - /** - * Update the control options. - * - * @param options options to update - */ - setOptions(options: OPTS) { - Object.assign(this.#options, options); - - const { - marker, - showResultMarkers, - flyTo, - fullGeometryStyle, - ...restOptions - } = this.#options; - - this.#gc?.$set(restOptions); - } - - /** - * Set the content of search input box. - * - * @param value text to set - * @param submit perform the search - */ - setQuery(value: string, submit = true) { - this.#gc?.setQuery(value, submit); - } - - /** - * Clear geocoding search results from the map. - */ - clearMap() { - this.#gc?.clearMap(); - } - - /** - * Clear search result list. - */ - clearList() { - this.#gc?.clearList(); - } - - /** - * Set reverse geocoding mode. - * - * @param reverseActive reverse geocoding active - */ - setReverseMode(reverseActive: boolean) { - this.#gc?.$set({ reverseActive }); - } - - /** - * Focus the search input box. - * - * @param options [FocusOptions](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus#options) - */ - focus(options?: FocusOptions) { - this.#gc?.focus(options); - } - - /** - * Blur the search input box. - */ - blur() { - this.#gc?.blur(); - } - - onRemove() { - this.#gc?.$destroy(); - - this.#gc = undefined; - - this.#container?.parentNode?.removeChild(this.#container); - } - } - - const events = { - SelectEvent, - FeaturesListedEvent, - FeaturesMarkedEvent, - OptionsVisibilityChangeEvent, - PickEvent, - QueryChangeEvent, - ResponseEvent, - ReverseToggleEvent, - } satisfies { - [T in keyof DispatcherTypeCC as `${Capitalize}Event`]: unknown; - }; - - return { - MapLibreBasedGeocodingControl, - - events, - }; -} diff --git a/src/MarkerIcon.svelte b/src/MarkerIcon.svelte deleted file mode 100644 index 1d6a115..0000000 --- a/src/MarkerIcon.svelte +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - diff --git a/src/ReverseGeocodingIcon.svelte b/src/ReverseGeocodingIcon.svelte deleted file mode 100644 index 6c41a59..0000000 --- a/src/ReverseGeocodingIcon.svelte +++ /dev/null @@ -1,12 +0,0 @@ - - - - - diff --git a/src/SearchIcon.svelte b/src/SearchIcon.svelte deleted file mode 100644 index e965410..0000000 --- a/src/SearchIcon.svelte +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - diff --git a/src/components/clear-icon.ts b/src/components/clear-icon.ts new file mode 100644 index 0000000..cac4feb --- /dev/null +++ b/src/components/clear-icon.ts @@ -0,0 +1,28 @@ +import { LitElement, css, svg } from "lit"; +import { customElement } from "lit/decorators.js"; + +@customElement("maptiler-geocode-clear-icon") +export class MaptilerGeocodeClearIconElement extends LitElement { + static styles = css` + svg { + display: block; + fill: var(--color-icon-button); + } + `; + + render() { + return svg` + + + + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "maptiler-geocode-clear-icon": MaptilerGeocodeClearIconElement; + } +} diff --git a/src/components/fail-icon.ts b/src/components/fail-icon.ts new file mode 100644 index 0000000..5a6cf94 --- /dev/null +++ b/src/components/fail-icon.ts @@ -0,0 +1,28 @@ +import { LitElement, css, svg } from "lit"; +import { customElement } from "lit/decorators.js"; + +@customElement("maptiler-geocode-fail-icon") +export class MaptilerGeocodeFailIconElement extends LitElement { + static styles = css` + svg { + display: block; + fill: #e15042; + } + `; + + render() { + return svg` + + + + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "maptiler-geocode-fail-icon": MaptilerGeocodeFailIconElement; + } +} diff --git a/src/components/loading-icon.ts b/src/components/loading-icon.ts new file mode 100644 index 0000000..eed4595 --- /dev/null +++ b/src/components/loading-icon.ts @@ -0,0 +1,50 @@ +import { LitElement, css, html } from "lit"; +import { customElement } from "lit/decorators.js"; + +@customElement("maptiler-geocode-loading-icon") +export class MaptilerGeocodeLoadingIconElement extends LitElement { + static styles = css` + div { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + pointer-events: none; + + display: flex; + align-items: center; + } + + .loading-icon { + animation: rotate 0.8s infinite cubic-bezier(0.45, 0.05, 0.55, 0.95); + } + + @keyframes rotate { + from { + -webkit-transform: rotate(0); + transform: rotate(0); + } + to { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } + } + `; + + render() { + return html` +
    + + + + +
    + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "maptiler-geocode-loading-icon": MaptilerGeocodeLoadingIconElement; + } +} diff --git a/src/components/marker.css b/src/components/marker.css new file mode 100644 index 0000000..97819cb --- /dev/null +++ b/src/components/marker.css @@ -0,0 +1,45 @@ +svg { + display: block; + fill: #6b7c93; + stroke: #6b7c93; + height: 30px; +} + +/* @TODO move extra styles to variables and outside of this component */ +/* :global(.maplibregl-canvas-container .marker-selected) { + z-index: 1; +} + +:global(.maplibregl-canvas-container) svg path, +:global(.leaflet-map-pane) svg path { + fill: #3170fe; + stroke: #3170fe; +} + +:global(.marker-selected) svg path { + fill: #98b7ff; + stroke: #3170fe; +} + +:global(.marker-reverse) svg path { + fill: silver; + stroke: gray; +} + +:global(.marker-interactive) { + cursor: pointer !important; +} + +/ * :global(.marker-fuzzy) svg path { + fill: silver; + stroke: gray; +} + +:global(.marker-fuzzy.marker-selected) svg path { + fill: #ddd; + stroke: silver; +} * / + +:global(.maptiler-gc-popup > .maplibregl-popup-content) { + padding: 2px 8px; +} */ diff --git a/src/components/marker.ts b/src/components/marker.ts new file mode 100644 index 0000000..373f26d --- /dev/null +++ b/src/components/marker.ts @@ -0,0 +1,32 @@ +import { LitElement, css, svg, unsafeCSS } from "lit"; +import { customElement } from "lit/decorators.js"; + +import styles from "./marker.css?inline"; + +@customElement("maptiler-geocode-marker") +export class MaptilerGeocodeMarkerElement extends LitElement { + static styles = css` + ${unsafeCSS(styles)} + `; + + render() { + return svg` + + + + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "maptiler-geocode-marker": MaptilerGeocodeMarkerElement; + } +} diff --git a/src/components/reverse-geocoding-icon.ts b/src/components/reverse-geocoding-icon.ts new file mode 100644 index 0000000..8dc99bd --- /dev/null +++ b/src/components/reverse-geocoding-icon.ts @@ -0,0 +1,28 @@ +import { LitElement, css, svg } from "lit"; +import { customElement } from "lit/decorators.js"; + +@customElement("maptiler-geocode-reverse-geocoding-icon") +export class MaptilerGeocodeReverseGeocodingIconElement extends LitElement { + static styles = css` + svg { + display: block; + fill: var(--color-icon-button); + } + `; + + render() { + return svg` + + + + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "maptiler-geocode-reverse-geocoding-icon": MaptilerGeocodeReverseGeocodingIconElement; + } +} diff --git a/src/components/search-icon.ts b/src/components/search-icon.ts new file mode 100644 index 0000000..9686f0e --- /dev/null +++ b/src/components/search-icon.ts @@ -0,0 +1,42 @@ +import { LitElement, css, svg } from "lit"; +import { customElement } from "lit/decorators.js"; + +@customElement("maptiler-geocode-search-icon") +export class MaptilerGeocodeSearchIconElement extends LitElement { + static styles = css` + circle { + stroke-width: 1.875; + fill: none; + } + + path { + stroke-width: 1.875; + stroke-linecap: round; + } + + svg { + display: block; + stroke: var(--color-icon-button); + } + `; + + render() { + return svg` + + + + + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "maptiler-geocode-search-icon": MaptilerGeocodeSearchIconElement; + } +} diff --git a/src/controls/maplibregl-control.ts b/src/controls/maplibregl-control.ts new file mode 100644 index 0000000..47d6580 --- /dev/null +++ b/src/controls/maplibregl-control.ts @@ -0,0 +1,567 @@ +import { feature, featureCollection } from "@turf/helpers"; +import union from "@turf/union"; +import type { GeoJSON, LineString, MultiLineString, MultiPolygon, Polygon } from "geojson"; +import maplibregl from "maplibre-gl"; + +import type { BBox, Feature, Position } from "../types"; +import { unwrapBbox } from "../utils/geo-utils"; +import { getMask } from "../utils/mask"; + +import "../geocoder/geocoder"; +import type { MaptilerGeocoderElement } from "../geocoder/geocoder"; +import type { + FeaturesListedEvent, + MaptilerGeocoderEventName, + MaptilerGeocoderEventNameMap, + PickEvent, + QueryChangeEvent, + RequestEvent, + ResponseEvent, + ReverseToggleEvent, + SelectEvent, +} from "../geocoder/geocoder-events"; + +import "../components/marker"; + +import type { MaplibreglGeocodingControlEventName, MaplibreglGeocodingControlEventNameMap } from "./maplibregl-events"; +import { DEFAULT_GEOMETRY_STYLE, type MaplibreglGeocodingControlOptions, RESULT_LAYER_FILL, RESULT_LAYER_LINE, RESULT_SOURCE, ZOOM_DEFAULTS } from "./maplibregl-options"; + +const Evented = maplibregl.Evented; +const Marker = maplibregl.Marker; +const Popup = maplibregl.Popup; +type Evented = maplibregl.Evented; +type GeoJSONSource = maplibregl.GeoJSONSource; +type IControl = maplibregl.IControl; +type MapMouseEvent = maplibregl.MapMouseEvent; +type Marker = maplibregl.Marker; +type MarkerOptions = maplibregl.MarkerOptions; +type MLMap = maplibregl.Map; +type MLEvent = Extract[0], object>; + +export class MaplibreglGeocodingControl extends Evented implements IControl { + #options: MaplibreglGeocodingControlOptions; + #map?: MLMap; + #element?: MaptilerGeocoderElement; + + constructor(options: MaplibreglGeocodingControlOptions = {}) { + super(); + this.#options = options; + } + + onAdd(map: MLMap): HTMLElement { + /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */ + // Check if Maptiler SDK is present + if ("getSdkConfig" in map && typeof map.getSdkConfig === "function") { + const { primaryLanguage, apiKey } = map.getSdkConfig(); + + if (this.#options.apiKey === undefined) { + this.#options.apiKey = apiKey; + } + + if (this.#options.language === undefined) { + const match = primaryLanguage.code?.match(/^([a-z]{2,3})($|_|-)/); + if (match) { + this.#options.language = match[1]; + } + } + } + /* eslint-enable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */ + + this.#map = map; + this.#element = map._container.ownerDocument.createElement("maptiler-geocoder"); + this.#setElementOptions(); + this.#addEventListeners(); + + const div = document.createElement("div"); + div.className = "mapboxgl-ctrl-geocoder mapboxgl-ctrl maplibregl-ctrl-geocoder maplibregl-ctrl mapboxgl-ctrl-group"; + div.appendChild(this.#element as Node); + return div; + } + + onRemove(): void { + this.#removeEventListeners(); + this.#map = undefined; + this.#element = undefined; + } + + /** + * Update the control options. + * + * @param options options to update + */ + setOptions(options: MaplibreglGeocodingControlOptions) { + Object.assign(this.#options, options); + this.#setElementOptions(); + } + + /** + * Set the content of search input box. + * + * @param value text to set + */ + setQuery(value: string) { + this.#element?.setQuery(value); + } + + /** + * Set the content of search input box and immediately submit it. + * + * @param value text to set and submit + */ + submitQuery(value: string) { + this.#element?.submitQuery(value); + } + + /** + * Clear geocoding search results from the map. + */ + clearMap() { + this.#markedFeatures = []; + this.#setFeatures(undefined, undefined); + } + + /** + * Clear search result list. + */ + clearList() { + this.#element?.clearList(); + } + + /** + * Set reverse geocoding mode. + * + * @param reverseActive reverse geocoding active + */ + setReverseMode(reverseActive: boolean) { + this.setOptions({ reverseActive }); + } + + /** + * Focus the search input box. + * + * @param options [FocusOptions](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus#options) + */ + focus(options?: FocusOptions) { + this.#element?.focus(options); + } + + /** + * Blur the search input box. + */ + blur() { + this.#element?.blur(); + } + + #markers = new Map(); + #selectedMarker: Marker | undefined; + #reverseMarker: Marker | undefined; + #markedFeatures?: Feature[]; + #savedData: GeoJSON | undefined; // used to restore features on style switch + #prevIdToFly?: string; // was not state nor prop before + + #elementEventListeners: { [EventName in MaptilerGeocoderEventName]: (e: MaptilerGeocoderEventNameMap[EventName]) => void } = { + reversetoggle: (event: ReverseToggleEvent) => { + const canvasContainer = this.#map?.getCanvasContainer(); + if (canvasContainer) { + canvasContainer.style.cursor = event.detail.reverse ? "crosshair" : ""; + } + this.#dispatch("reversetoggle", event.detail); + }, + querychange: (event: QueryChangeEvent) => { + const coords = (event as QueryChangeEvent).detail.reverseCoords; + + this.#setReverseMarker(coords ? [coords.decimalLongitude, coords.decimalLatitude] : undefined); + this.#dispatch("querychange", event.detail); + }, + queryclear: () => { + this.#setReverseMarker(undefined); + this.#dispatch("queryclear"); + }, + request: (event: RequestEvent) => { + this.#dispatch("request", event.detail); + }, + response: (event: ResponseEvent) => { + this.#dispatch("response", event.detail); + }, + select: (event: SelectEvent) => { + const selected = (event as SelectEvent).detail.feature; + if (selected && this.#flyToEnabled && this.#options.flyToSelected) { + this.#flyTo(selected.center, this.#computeZoom(selected)); + } + if (this.#markedFeatures && selected) { + this.#setSelectedMarker(selected); + } + this.#dispatch("select", event.detail); + }, + pick: (event: PickEvent) => { + const picked = (event as PickEvent).detail.feature; + if (picked && picked.id !== this.#prevIdToFly && this.#flyToEnabled) { + this.#goToPicked(picked); + this.#setFeatures(this.#markedFeatures, picked); + } + + this.#prevIdToFly = picked?.id; + + this.#dispatch("pick", event.detail); + }, + featuresshow: () => { + this.#dispatch("featuresshow"); + }, + featureshide: () => { + this.#dispatch("featureshide"); + }, + featureslisted: (event: FeaturesListedEvent) => { + const features = (event as FeaturesListedEvent).detail.features; + this.#markedFeatures = features; + this.#setFeatures(this.#markedFeatures, undefined); + this.#zoomToResults(features); + this.#dispatch("featureslisted", event.detail); + }, + featuresclear: () => { + this.#markedFeatures = undefined; + this.#setFeatures(undefined, undefined); + this.#dispatch("featuresclear"); + }, + focusin: () => { + this.#dispatch("focusin"); + }, + focusout: () => { + this.#dispatch("focusout"); + }, + }; + #mapEventListeners = { + render: () => { + const zoom = this.#map?.getZoom(); + const center = this.#map?.getCenter(); + this.#element?.handleMapChange(zoom && center ? [zoom, center.lng, center.lat] : undefined); + }, + click: (e: MapMouseEvent) => { + this.#element?.handleMapClick([e.lngLat.lng, e.lngLat.lat]); + }, + styledata: () => { + setTimeout(() => { + if (this.#savedData) { + this.#syncFullGeometryLayer(); + } + }); + }, + }; + + #setElementOptions() { + if (!this.#element) return; + + this.#element.setOptions(this.#options); + this.#element.fetchFullGeometryOnPick = this.#options.pickedResultStyle !== "marker-only"; + } + + #addEventListeners() { + if (!this.#element || !this.#map) return; + + for (const [type, listener] of Object.entries(this.#elementEventListeners)) { + this.#element.addEventListener(type as MaptilerGeocoderEventName, listener as EventListener); + } + + for (const [type, listener] of Object.entries(this.#mapEventListeners)) { + this.#map.on(type, listener); + } + } + + #removeEventListeners() { + if (!this.#element || !this.#map) return; + + for (const [type, listener] of Object.entries(this.#elementEventListeners)) { + this.#element.removeEventListener(type as MaptilerGeocoderEventName, listener as EventListener); + } + + for (const [type, listener] of Object.entries(this.#mapEventListeners)) { + this.#map.off(type, listener); + } + } + + #dispatch(type: E, detail?: MaplibreglGeocodingControlEventNameMap[E]): this { + return super.fire({ type, ...(detail ?? {}) } as MLEvent); + } + + #goToPicked(picked: Feature) { + if (picked.bbox[0] === picked.bbox[2] && picked.bbox[1] === picked.bbox[3]) { + this.#flyTo(picked.center, this.#computeZoom(picked)); + } else { + this.#fitBounds(unwrapBbox(picked.bbox), 50, this.#computeZoom(picked)); + } + } + + #zoomToResults(features: Feature[] | undefined) { + if (!features || features.length === 0 || !this.#flyToEnabled) return; + + const fuzzyOnly = features.every((feature) => feature.matching_text); + const bbox = features.reduce( + (bbox, feature) => + fuzzyOnly || !feature.matching_text + ? [Math.min(bbox[0], feature.bbox[0]), Math.min(bbox[1], feature.bbox[1]), Math.max(bbox[2], feature.bbox[2]), Math.max(bbox[3], feature.bbox[3])] + : bbox, + [180, 90, -180, -90], + ); + + const allZoom = features + .map((feature) => this.#computeZoom(feature)) + .filter((zoom) => zoom !== undefined) + .reduce((allZoom, featZoom) => (allZoom === undefined ? featZoom : Math.max(allZoom, featZoom)), undefined); + + this.#fitBounds(unwrapBbox(bbox), 50, allZoom); + } + + #computeZoom(feature: Feature): number | undefined { + if (feature.bbox[0] !== feature.bbox[2] || feature.bbox[1] !== feature.bbox[3]) { + return undefined; + } + + const index = feature.id.replace(/\..*/, ""); + const zoomMap = this.#options.zoom ?? ZOOM_DEFAULTS; + + return ( + (Array.isArray(feature.properties?.categories) + ? (feature.properties.categories as string[]).reduce((a, category) => { + const b = zoomMap[index + "." + category] as number | undefined; + + return a === undefined ? b : b === undefined ? a : Math.max(a, b); + }, undefined) + : undefined) ?? zoomMap[index] + ); + } + + get #flyToEnabled() { + return Boolean(this.#options.flyTo) || this.#options.flyTo === undefined; + } + get #flyToOptions() { + return typeof this.#options.flyTo === "boolean" ? {} : this.#options.flyTo; + } + get #fitBoundsOptions() { + return typeof this.#options.flyTo === "boolean" ? {} : this.#options.flyTo; + } + + #flyTo(center: Position, zoom?: number): void { + this.#map?.flyTo({ center, ...(zoom ? { zoom } : {}), ...this.#flyToOptions }); + } + + #fitBounds(bbox: BBox, padding: number, maxZoom?: number): void { + this.#map?.fitBounds( + [ + [bbox[0], bbox[1]], + [bbox[2], bbox[3]], + ], + { padding, ...(maxZoom ? { maxZoom } : {}), ...this.#fitBoundsOptions }, + ); + } + + #setReverseMarker(coordinates?: Position) { + if (this.#options.marker === false || this.#options.marker === null || !this.#map) { + return; + } + + if (this.#reverseMarker) { + if (!coordinates) { + this.#reverseMarker.remove(); + + this.#reverseMarker = undefined; + } else { + this.#reverseMarker.setLngLat(coordinates); + } + } else if (coordinates) { + if (this.#options.marker instanceof Function) { + this.#reverseMarker = this.#options.marker(this.#map) ?? undefined; + } else { + this.#reverseMarker = this.#createMarker(this.#options.marker).setLngLat(coordinates).addTo(this.#map); + this.#reverseMarker.getElement().classList.add("marker-reverse"); + } + } + } + + #setFeatures(markedFeatures: Feature[] | undefined, picked: Feature | undefined): void { + if (!this.#map) { + return; + } + + for (const marker of this.#markers.values()) { + marker.remove(); + } + + this.#markers = new Map(); + + this.#setAndSaveData(undefined); + + const addMarker = () => { + if (!picked || !this.#map || this.#options.marker === false || this.#options.marker === null) return; + + const marker = + this.#options.marker instanceof Function ? this.#options.marker(this.#map, picked) : this.#createMarker(this.#options.marker).setLngLat(picked.center).addTo(this.#map); + if (marker) { + this.#markers.set(picked, marker); + } + }; + + if (picked?.geometry.type === "GeometryCollection") { + const polygonGeometries = picked.geometry.geometries.filter( + (geometry): geometry is Polygon | MultiPolygon => geometry.type === "Polygon" || geometry.type === "MultiPolygon", + ); + + if (polygonGeometries.length > 0) { + const unioned = union(featureCollection(polygonGeometries.map((geom) => feature(geom)))); + + if (unioned) { + const mask = getMask({ ...picked, geometry: unioned.geometry }); + if (mask) { + this.#setAndSaveData(mask); + } + } + } else { + const lineGeometries = picked.geometry.geometries.filter( + (geometry): geometry is LineString | MultiLineString => geometry.type === "LineString" || geometry.type === "MultiLineString", + ); + + if (lineGeometries.length > 0) { + this.#setAndSaveData({ + ...picked, + geometry: { type: "GeometryCollection", geometries: lineGeometries }, + }); + } + } + } else if (picked?.geometry.type.endsWith("Polygon")) { + const mask = getMask(picked as Feature); + if (mask) { + this.#setAndSaveData(mask); + } + if (this.#options.pickedResultStyle === "full-geometry-including-polygon-center-marker") { + addMarker(); + } + } else if (picked?.geometry.type.endsWith("LineString")) { + this.#setAndSaveData(picked); + } else if (picked?.geometry.type.endsWith("Point")) { + addMarker(); + } + + if (this.#options.showResultMarkers !== false && this.#options.showResultMarkers !== null) { + for (const feature of markedFeatures ?? []) { + if (feature.id === picked?.id) { + continue; + } + + let marker; + + if (this.#options.showResultMarkers instanceof Function) { + marker = this.#options.showResultMarkers(this.#map, feature); + + if (!marker) { + continue; + } + } else { + marker = this.#createMarker(this.#options.showResultMarkers) + .setLngLat(feature.center) + .setPopup( + new Popup({ + offset: [1, -27], + closeButton: false, + closeOnMove: true, + className: "maptiler-gc-popup", + }).setText(feature.place_type[0] === "reverse" ? feature.place_name : feature.place_name.replace(/,.*/, "")), + ) + .addTo(this.#map); + + marker.getElement().classList.add("marker-interactive"); + } + + const element = marker.getElement(); + + element.addEventListener("click", (e) => { + e.stopPropagation(); + this.#dispatch("markerclick", { feature, marker }); + }); + + element.addEventListener("mouseenter", () => { + this.#dispatch("markermouseenter", { feature, marker }); + marker.togglePopup(); + }); + + element.addEventListener("mouseleave", () => { + this.#dispatch("markermouseleave", { feature, marker }); + marker.togglePopup(); + }); + + // element.classList.toggle("marker-fuzzy", !!feature.matching_text); + + this.#markers.set(feature, marker); + } + } + } + + #setSelectedMarker(feature: Feature): void { + this.#selectedMarker?.getElement().classList.toggle("marker-selected", false); + + if (this.#options.markerOnSelected) { + this.#selectedMarker = this.#markers.get(feature); + this.#selectedMarker?.getElement().classList.toggle("marker-selected", true); + } else if (this.#selectedMarker) { + this.#selectedMarker = undefined; + } + } + + #syncFullGeometryLayer() { + if (!this.#map?.loaded) { + void this.#map?.once("load", () => { + this.#syncFullGeometryLayer(); + }); + return; + } + + const effFullGeometryStyle = + this.#options.fullGeometryStyle === undefined || this.#options.fullGeometryStyle === true + ? DEFAULT_GEOMETRY_STYLE + : !this.#options.fullGeometryStyle + ? undefined + : this.#options.fullGeometryStyle; + const source = this.#map.getSource(RESULT_SOURCE); + + if ((!effFullGeometryStyle?.fill && !effFullGeometryStyle?.line) || (!source && !this.#savedData)) { + return; + } + + if (source) { + source.setData(this.#savedData ?? featureCollection([])); + } else if (this.#savedData) { + this.#map.addSource(RESULT_SOURCE, { + type: "geojson", + data: this.#savedData, + }); + } + + if (!this.#map.getLayer(RESULT_LAYER_FILL) && effFullGeometryStyle.fill) { + this.#map.addLayer({ + ...effFullGeometryStyle.fill, + id: RESULT_LAYER_FILL, + type: "fill", + source: RESULT_SOURCE, + }); + } + + if (!this.#map.getLayer(RESULT_LAYER_LINE) && effFullGeometryStyle.line) { + this.#map.addLayer({ + ...effFullGeometryStyle.line, + id: RESULT_LAYER_LINE, + type: "line", + source: RESULT_SOURCE, + }); + } + } + + #setAndSaveData(data?: GeoJSON) { + this.#savedData = data; + + this.#syncFullGeometryLayer(); + } + + #createMarker(options: MarkerOptions | true | undefined) { + if (typeof options !== "object") { + options = { element: this.#map?._container.ownerDocument.createElement("maptiler-geocode-marker"), offset: [1, -13] }; + } + return new Marker(options); + } +} diff --git a/src/controls/maplibregl-events.ts b/src/controls/maplibregl-events.ts new file mode 100644 index 0000000..af2a30e --- /dev/null +++ b/src/controls/maplibregl-events.ts @@ -0,0 +1,39 @@ +import maplibregl from "maplibre-gl"; +import type { Feature } from "../types"; +type Marker = maplibregl.Marker; + +import type * as Geocoder from "../geocoder/geocoder-events"; + +export type ReverseToggleEvent = Geocoder.ReverseToggleEvent["detail"]; +export type QueryChangeEvent = Geocoder.QueryChangeEvent["detail"]; +export type FeaturesListedEvent = Geocoder.FeaturesListedEvent["detail"]; +export type RequestEvent = Geocoder.RequestEvent["detail"]; +export type ResponseEvent = Geocoder.ResponseEvent["detail"]; +export type SelectEvent = Geocoder.SelectEvent["detail"]; +export type PickEvent = Geocoder.PickEvent["detail"]; +export type MarkerClickEvent = { feature: Feature; marker: Marker }; +export type MarkerMouseEnterEvent = { feature: Feature; marker: Marker }; +export type MarkerMouseLeaveEvent = { feature: Feature; marker: Marker }; +export type MaplibreglGeocodingControlEventNameMap = { + reversetoggle: ReverseToggleEvent; + querychange: QueryChangeEvent; + queryclear: never; + request: RequestEvent; + response: ResponseEvent; + select: SelectEvent; + pick: PickEvent; + featuresshow: never; + featureshide: never; + featureslisted: FeaturesListedEvent; + featuresclear: never; + + focusin: never; + focusout: never; + + markerclick: MarkerClickEvent; + markermouseenter: MarkerMouseEnterEvent; + markermouseleave: MarkerMouseLeaveEvent; +}; + +export type MaplibreglGeocodingControlEvent = MaplibreglGeocodingControlEventNameMap[keyof MaplibreglGeocodingControlEventNameMap]; +export type MaplibreglGeocodingControlEventName = keyof MaplibreglGeocodingControlEventNameMap; diff --git a/src/controls/maplibregl-options.ts b/src/controls/maplibregl-options.ts new file mode 100644 index 0000000..d76bf49 --- /dev/null +++ b/src/controls/maplibregl-options.ts @@ -0,0 +1,165 @@ +import maplibregl from "maplibre-gl"; + +type FillLayerSpecification = maplibregl.FillLayerSpecification; +type FitBoundsOptions = maplibregl.FitBoundsOptions; +type FlyToOptions = maplibregl.FlyToOptions; +type LineLayerSpecification = maplibregl.LineLayerSpecification; +type Marker = maplibregl.Marker; +type MarkerOptions = maplibregl.MarkerOptions; +type MLMap = maplibregl.Map; + +import type { MaptilerGeocoderOptions } from "../geocoder/geocoder-options"; +import type { Feature, PickedResultStyle } from "../types"; + +export type MaplibreglGeocodingControlOptions = Omit & { + /** + * Maptiler API key. Optional if used with MapTiler SDK - if not specified, the control will use the same API key as the map uses. + */ + apiKey?: string; + + /** + * Marker to be added to the map at the location of the user-selected result using a default set of Marker options. + * + * - If `true` or `undefined` then a default marker will be used. + * - If the value is a [MarkerOptions](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/MarkerOptions/) then the marker will be constructed using these options. + * - If the value is a function then it can return instance of the [Marker](https://maplibre.org/maplibre-gl-js/docs/API/classes/Marker/). + * Function can accept `Feature` as a parameter which is `undefined` for the reverse location marker. + * - If `false` or `null` then no marker will be added to the map. + * + * Requires that `options.maplibregl` also be set. + * + * Default value is `true`. + */ + marker?: null | boolean | MarkerOptions | ((map: MLMap, feature?: Feature) => undefined | null | Marker); + + /** + * Displays a marker on the selected feature from the result list. `marker` must be enabled in any way for this to display. + * + * Default: `true`. + */ + markerOnSelected?: boolean; + + /** + * Marker be added to the map at the location the geocoding results. + * + * - If `true` or `undefined` then a default marker will be used. + * - If the value is a [MarkerOptions](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/MarkerOptions/) then the marker will be constructed using these options. + * - If the value is a function then it can return instance of the [Marker](https://maplibre.org/maplibre-gl-js/docs/API/classes/Marker/). + * In this case the default pop-up won't be added to the marker. + * Function can accept `Feature` as a parameter. + * - If `false` or `null` then no marker will be added to the map. + * + * Requires that `options.maplibregl` also be set. + * + * Default value is `true`. + */ + showResultMarkers?: null | boolean | MarkerOptions | ((map: MLMap, feature: Feature) => undefined | null | Marker); + + /** + * Animation to picked feature on the map. + * + * - If `false` or `null` then animating the map to a selected result is disabled. + * - If `true` or `undefined` then animating the map will use the default animation parameters. + * - If an [FlyToOptions](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/FlyToOptions/) + * ` & `[FitBoundsOptions](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/FitBoundsOptions/) + * then it will be passed as options to the map [flyTo](https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/#flyto) + * or [fitBounds](https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/#fitbounds) method providing control over the animation of the transition. + * + * Default value is `true`. + */ + flyTo?: null | boolean | (FlyToOptions & FitBoundsOptions); + + /** + * Specifies if selected (not picked) feature should be also animated to on the map. + * + * Default: `false`. + */ + flyToSelected?: boolean; + + /** + * Style for full feature geometry GeoJSON. + * + * - If `false` or `null` then no full geometry is drawn. + * - If `true` or `undefined` then default-styled full geometry is drawn. + * - If an T then it must represent the style and will be used to style the full geometry. + * + * Default is the default style. + */ + fullGeometryStyle?: null | boolean | Partial; + + /** + * Style of the picked result on the map: + * - `"marker-only"`: Show only a marker at the center of the feature. + * - `"full-geometry"`: Display the full feature geometry. + * - `"full-geometry-including-polygon-center-marker"`: Display full geometry with a marker at the polygon center. + * + * Default: `"full-geometry"`. + */ + pickedResultStyle?: PickedResultStyle; + + /** + * Specifies the zoom level to animate the map to for a geocoded result when no bounding box is present or when the result is a point. + * If a bounding box is present and not a point, the map will fit to the bounding box. + * + * Values are key-value pairs where the key is a `` or `.` and the value is the zoom level. + * + * Default: `ZOOM_DEFAULTS`. + */ + zoom?: Record; +}; + +export type FullGeometryStyle = { + fill: Pick; + line: Pick; +}; + +export const ZOOM_DEFAULTS: Record = { + continental_marine: 4, + country: 4, + major_landform: 8, + region: 5, + subregion: 6, + county: 7, + joint_municipality: 8, + joint_submunicipality: 9, + municipality: 10, + municipal_district: 11, + locality: 12, + neighbourhood: 13, + place: 14, + postal_code: 14, + road: 16, + poi: 17, + address: 18, + "poi.peak": 15, + "poi.shop": 18, + "poi.cafe": 18, + "poi.restaurant": 18, + "poi.aerodrome": 13, + // TODO add many more +}; + +export const DEFAULT_GEOMETRY_STYLE: FullGeometryStyle = { + fill: { + paint: { + "fill-color": "#000", + "fill-opacity": 0.1, + }, + filter: ["all", ["==", ["geometry-type"], "Polygon"], ["has", "isMask"]], + }, + line: { + layout: { + "line-cap": "square", + }, + paint: { + "line-width": ["case", ["==", ["geometry-type"], "Polygon"], 2, 3], + "line-dasharray": [1, 1], + "line-color": "#3170fe", + }, + filter: ["!", ["has", "isMask"]], + }, +}; + +export const RESULT_SOURCE = "mtlr-gc-full-geom"; +export const RESULT_LAYER_FILL = "mtlr-gc-full-geom-fill"; +export const RESULT_LAYER_LINE = "mtlr-gc-full-geom-line"; diff --git a/src/controls/maptilersdk-control.ts b/src/controls/maptilersdk-control.ts new file mode 100644 index 0000000..6948670 --- /dev/null +++ b/src/controls/maptilersdk-control.ts @@ -0,0 +1,12 @@ +import { MaplibreglGeocodingControl } from "./maplibregl-control"; +import type { MaptilerGeocodingControlOptions } from "./maptilersdk-options"; + +export class MaptilerGeocodingControl extends MaplibreglGeocodingControl { + constructor(options: MaptilerGeocodingControlOptions = {}) { + super(options); + } + + override setOptions(options: MaptilerGeocodingControlOptions) { + super.setOptions(options); + } +} diff --git a/src/controls/maptilersdk-events.ts b/src/controls/maptilersdk-events.ts new file mode 100644 index 0000000..d931439 --- /dev/null +++ b/src/controls/maptilersdk-events.ts @@ -0,0 +1,31 @@ +import type { + FeaturesListedEvent, + MaplibreglGeocodingControlEvent, + MaplibreglGeocodingControlEventName, + MaplibreglGeocodingControlEventNameMap, + MarkerClickEvent, + MarkerMouseEnterEvent, + MarkerMouseLeaveEvent, + PickEvent, + QueryChangeEvent, + RequestEvent, + ResponseEvent, + ReverseToggleEvent, + SelectEvent, +} from "./maplibregl-events"; + +export type { + FeaturesListedEvent, + MaplibreglGeocodingControlEvent as MaptilerGeocodingControlEvent, + MaplibreglGeocodingControlEventName as MaptilerGeocodingControlEventName, + MaplibreglGeocodingControlEventNameMap as MaptilerGeocodingControlEventNameMap, + MarkerClickEvent, + MarkerMouseEnterEvent, + MarkerMouseLeaveEvent, + PickEvent, + QueryChangeEvent, + RequestEvent, + ResponseEvent, + ReverseToggleEvent, + SelectEvent, +}; diff --git a/src/controls/maptilersdk-options.ts b/src/controls/maptilersdk-options.ts new file mode 100644 index 0000000..9804bfe --- /dev/null +++ b/src/controls/maptilersdk-options.ts @@ -0,0 +1,12 @@ +import type { MaplibreglGeocodingControlOptions } from "./maplibregl-options"; + +export type MaptilerGeocodingControlOptions = Omit & { + /** + * Maptiler API key. + * + * Default: The same API key as the connected map uses. + */ + apiKey?: string; +}; + +export { DEFAULT_GEOMETRY_STYLE, RESULT_LAYER_FILL, RESULT_LAYER_LINE, RESULT_SOURCE, ZOOM_DEFAULTS, type FullGeometryStyle } from "./maplibregl-options"; diff --git a/src/geo-coordinates-parser.t.ts b/src/geo-coordinates-parser.t.ts deleted file mode 100644 index a6eee2e..0000000 --- a/src/geo-coordinates-parser.t.ts +++ /dev/null @@ -1,11 +0,0 @@ -declare module "geo-coordinates-parser" { - export function convert( - input: string, - decimalPlaces: number, - ): { - decimalLatitude: number; - decimalLongitude: number; - verbatimLatitude: string; - verbatimLongitude: string; - }; -} diff --git a/src/geocoder/geocoder-events.ts b/src/geocoder/geocoder-events.ts new file mode 100644 index 0000000..6916239 --- /dev/null +++ b/src/geocoder/geocoder-events.ts @@ -0,0 +1,34 @@ +import type { convert } from "geo-coordinates-parser"; +import type { Feature, FeatureCollection } from "../types"; + +export type ReverseToggleEvent = CustomEvent<{ reverse: boolean }>; +export type QueryChangeEvent = CustomEvent<{ query: string; reverseCoords: ReturnType | false }>; +export type QueryClearEvent = CustomEvent; +export type RequestEvent = CustomEvent<{ urlObj: URL }>; +export type ResponseEvent = CustomEvent<{ url: string; featureCollection: FeatureCollection }>; +export type SelectEvent = CustomEvent<{ feature: Feature | undefined }>; +export type PickEvent = CustomEvent<{ feature: Feature | undefined }>; +export type FeaturesShowEvent = CustomEvent; +export type FeaturesHideEvent = CustomEvent; +export type FeaturesListedEvent = CustomEvent<{ features: Feature[] | undefined }>; +export type FeaturesClearEvent = CustomEvent; + +export type MaptilerGeocoderEventNameMap = { + reversetoggle: ReverseToggleEvent; + querychange: QueryChangeEvent; + queryclear: QueryClearEvent; + request: RequestEvent; + response: ResponseEvent; + select: SelectEvent; + pick: PickEvent; + featuresshow: FeaturesShowEvent; + featureshide: FeaturesHideEvent; + featureslisted: FeaturesListedEvent; + featuresclear: FeaturesClearEvent; + + focusin: FocusEvent; + focusout: FocusEvent; +}; + +export type MaptilerGeocoderEvent = MaptilerGeocoderEventNameMap[keyof MaptilerGeocoderEventNameMap]; +export type MaptilerGeocoderEventName = keyof MaptilerGeocoderEventNameMap; diff --git a/src/geocoder/geocoder-feature-item.css b/src/geocoder/geocoder-feature-item.css new file mode 100644 index 0000000..42478fa --- /dev/null +++ b/src/geocoder/geocoder-feature-item.css @@ -0,0 +1,111 @@ +.sprite-icon { + align-self: center; + justify-self: center; + opacity: 0.75; + background-repeat: no-repeat; +} + +li { + text-align: left; + cursor: default; + display: grid; + grid-template-columns: 40px 1fr; + color: var(--color-text); + padding: 8px 0px; + font-size: 14px; + line-height: 18px; + min-width: fit-content; + outline: 0; + + &:first-child { + padding-top: 10px; + } + + &:last-child { + padding-bottom: 10px; + } + + &.picked { + background-color: #e7edff; + + .secondary { + color: #96a4c7; + padding-left: 4px; + } + + .line2 { + color: #96a4c7; + } + } + + &.selected { + background-color: #f3f6ff; + + & { + animation: backAndForth 5s linear infinite; + } + + & .primary { + color: #2b8bfb; + } + + .secondary { + color: #a2adc7; + padding-left: 4px; + } + + .line2 { + color: #a2adc7; + } + } + + & > img { + align-self: center; + justify-self: center; + opacity: 0.75; + } +} + +.texts { + padding: 0 17px 0 0; + + & > * { + white-space: nowrap; + display: block; + min-width: fit-content; + } +} + +.primary { + font-weight: 600; +} + +.secondary { + color: #aeb6c7; + padding-left: 4px; +} + +.line2 { + color: #aeb6c7; +} + +@keyframes backAndForth { + 0% { + transform: translateX(0); + } + 10% { + transform: translateX(0); + } + 45% { + transform: translateX(calc(-100% + 270px)); + } + 55% { + transform: translateX(calc(-100% + 270px)); + } + 90% { + transform: translateX(0); + } + 100% { + transform: translateX(0); + } +} diff --git a/src/geocoder/geocoder-feature-item.ts b/src/geocoder/geocoder-feature-item.ts new file mode 100644 index 0000000..76ab438 --- /dev/null +++ b/src/geocoder/geocoder-feature-item.ts @@ -0,0 +1,176 @@ +/* eslint-disable +@typescript-eslint/no-unnecessary-condition, + @typescript-eslint/no-unsafe-assignment, + @typescript-eslint/no-unsafe-call, + @typescript-eslint/no-unsafe-member-access, + @typescript-eslint/no-unsafe-return, + @typescript-eslint/restrict-template-expressions, + @typescript-eslint/unbound-method, +*/ +import { LitElement, css, html, nothing, unsafeCSS } from "lit"; +import { customElement, property, state } from "lit/decorators.js"; +import { styleMap } from "lit/directives/style-map.js"; + +import type { Feature, ShowPlaceType } from "../types"; +import styles from "./geocoder-feature-item.css?inline"; + +type SpriteIcon = { width: number; height: number; x: number; y: number }; + +const hidpi = typeof devicePixelRatio === "undefined" || devicePixelRatio > 1.25; + +const scaleUrl = hidpi ? "@2x" : ""; + +const scaleFactor = hidpi ? 2 : 1; + +let sprites: undefined | null | { width: number; height: number; icons: Record }; + +let spritePromise: Promise | undefined; + +@customElement("maptiler-geocoder-feature-item") +export class MaptilerGeocoderFeatureItemElement extends LitElement { + static styles = css` + ${unsafeCSS(styles)} + `; + + @property({ type: Object }) feature?: Feature; + @property({ type: String }) itemStyle: "selected" | "picked" | "default" = "default"; + @property({ type: String }) showPlaceType: ShowPlaceType = "if-needed"; + @property({ attribute: false }) missingIconsCache: Set = new Set(); + @property({ type: String }) iconsBaseUrl: string = ""; + + get #categories() { + return this.feature?.properties?.categories; + } + get #isReverse() { + return this.feature?.place_type[0] === "reverse"; + } + get #placeType() { + return this.feature?.properties?.categories?.join(", ") ?? this.feature?.place_type_name?.[0] ?? this.feature?.place_type[0]; + } + + @state() private category: string | undefined; + @state() private imageUrl: string | undefined; + @state() private spriteIcon: SpriteIcon | undefined; + @state() private index: number = 0; + + // $: { + // index = categories?.length ?? 0; + + // loadIcon(); + // } + + #loadSprites() { + spritePromise ??= fetch(`${this.iconsBaseUrl}sprite${scaleUrl}.json`) + .then((response) => response.json()) + .then((data) => { + sprites = data; + }) + .catch(() => { + sprites = null; + }); + } + + #handleImgError() { + if (this.imageUrl) { + this.missingIconsCache.add(this.imageUrl); + } + + this.#loadIcon(); + } + + #loadIcon() { + if (sprites !== undefined) { + this.#loadIcon2(); + } else { + this.#loadSprites(); + + void spritePromise?.then(() => { + this.#loadIcon2(); + }); + } + } + + #loadIcon2() { + do { + this.index--; + + this.category = this.#categories?.[this.index]; + + this.spriteIcon = this.category ? sprites?.icons[this.category] : undefined; + + if (this.spriteIcon) { + break; + } + + this.imageUrl = this.category ? this.iconsBaseUrl + this.category.replace(/ /g, "_") + ".svg" : undefined; + } while (this.index > -1 && (!this.imageUrl || this.missingIconsCache.has(this.imageUrl))); + } + + render() { + return html` +
  • this.dispatchEvent(new CustomEvent("select"))} + > + ${sprites && this.spriteIcon + ? html` +
    + ` + : this.imageUrl + ? html` ${this.category}` + : this.feature?.address + ? html` ${this.#placeType} ` + : this.feature?.id.startsWith("road.") + ? html` ${this.#placeType} ` + : this.feature?.id.startsWith("address.") + ? html` ${this.#placeType} ` + : this.feature?.id.startsWith("postal_code.") + ? html` ${this.#placeType} ` + : this.feature?.id.startsWith("poi.") + ? html` ${this.#placeType} ` + : this.#isReverse + ? html` ${this.#placeType} ` + : html` ${this.#placeType} `} + + + + ${this.#isReverse ? this.feature?.place_name : this.feature?.place_name.replace(/,.*/, "")} + + ${this.showPlaceType === "always" || + (this.showPlaceType !== "never" && + !this.feature?.address && + !this.feature?.id.startsWith("road.") && + !this.feature?.id.startsWith("address.") && + !this.feature?.id.startsWith("postal_code.") && + (!this.feature?.id.startsWith("poi.") || !this.imageUrl) && + !this.#isReverse) + ? html` ${this.#placeType} ` + : nothing} + + + ${this.#isReverse ? "" : this.feature?.place_name.replace(/[^,]*,?s*/, "")} + +
  • + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "maptiler-geocoder-feature-item": MaptilerGeocoderFeatureItemElement; + } +} diff --git a/src/geocoder/geocoder-options.ts b/src/geocoder/geocoder-options.ts new file mode 100644 index 0000000..4939c3d --- /dev/null +++ b/src/geocoder/geocoder-options.ts @@ -0,0 +1,291 @@ +import type { BBox, EnableReverse, Feature, ProximityRule, ShowPlaceType, TypeRule } from "../types"; + +export type MaptilerGeocoderOptions = { + /** + * Callback function to adjust the geocoding URL before fetching. + * + * @param url [URL](https://developer.mozilla.org/en-US/docs/Web/API/URL) parameter that can be modified. + * + * Default: Empty function. + */ + adjustUrl?: (url: URL) => void; + + /** + * MapTiler API key. + */ + apiKey?: string; + + /** + * Geocoding API URL. + * + * Default: MapTiler Geocoding API URL. + */ + apiUrl?: string; + + /** + * Bounding box in the format `[minX, minY, maxX, maxY]` to limit search results. + * + * Default: `undefined`. + */ + bbox?: BBox; + + /** + * CSS class for the root element. + * + * Default: `undefined`. + */ + class?: string; + + /** + * Title of the clear button. + * + * Default: `"clear"`. + */ + clearButtonTitle?: string; + + /** + * Clears the result list after picking an item. + * Prevents redisplaying the list when the input box is focused. + * + * Default: `false`. + */ + clearListOnPick?: boolean; + + /** + * Clears the input value when it loses focus. + * + * Default: `false`. + */ + clearOnBlur?: boolean; + + /** + * Collapses the geocoder control until hovered or focused. + * + * Default: `false`. + */ + collapsed?: boolean; + + /** + * Limits search to the specified country or countries. + * + * Default: `undefined` (all countries). + */ + country?: string | string[]; + + /** + * Time delay (in milliseconds) before querying the server after typing in the input box. + * Useful for reducing the number of API calls. + * + * Default: `200`. + */ + debounceSearch?: number; + + /** + * Enables reverse geocoding: + * - `"button"`: Enables reverse geocoding button. + * - `"always"`: Reverse geocoding is always active. + * + * Default: `"never"`. + */ + enableReverse?: EnableReverse; + + /** + * Custom error message. + * + * Default: `"Something went wrong…"`. + */ + errorMessage?: string; + + /** + * Includes all available types except those listed in the `types` option. + * + * See `reverseGeocodingExcludeTypes` for reverse geocoding exclusion. + * + * Default: `false`. + */ + excludeTypes?: boolean; + + /** + * Uses the `limit` option value for reverse geocoding even if the `types` option has multiple elements. + * Works only if enabled on the server. + * + * Default: `false`. + */ + exhaustiveReverseGeocoding?: boolean; + + /** + * Enables fetching the full geometry (polygon etc.) instead of just a point on a picked feature. + * + * Default: `false`. + */ + fetchFullGeometryOnPick?: boolean; + + /** + * Additional parameters for fetch requests. + * + * Default: `undefined`. + */ + fetchParameters?: RequestInit; + + /** + * Callback function to filter results from the Geocoding API response. + * The function should return `true` to keep an item, or `false` to exclude it. + * + * Default: A function that always returns `true`. + */ + filter?: (feature: Feature) => boolean; + + /** + * Enables fuzzy search. + * + * Default: `true`. + */ + fuzzyMatch?: boolean; + + /** + * Base URL for POI icons. + * + * Default: + * - `"icons/"` for Svelte apps. + * - `"https://cdn.maptiler.com/maptiler-geocoding-control/v${version}/icons/"` for others. + */ + iconsBaseUrl?: string; + + /** + * Keeps the result list open even if the control is unfocused. + * + * Default: `false`. + */ + keepListOpen?: boolean; + + /** + * Language for response text and query weighting. + * Accepts IETF language tags. + * Set to `null` or an empty string to disable language-specific searching. + * + * Default: `undefined` (uses the browser's language settings). + */ + language?: string | string[] | null; + + /** + * Maximum number of results to display. + * + * See `reverseGeocodingLimit` for reverse geocoding limits. + * + * Default: `5`. + */ + limit?: number; + + /** + * Minimum number of characters required to start a search. + * + * Default: `2`. + */ + minLength?: number; + + /** + * Custom message for when no results are found. + * + * Default: + * ``` + * "Oops! Looks like you're trying to predict something that's not quite right. + * We can't seem to find what you're looking for. Maybe try double-checking your spelling or try a different search term. + * Keep on typing - we'll do our best to get you where you need to go!" + * ``` + */ + noResultsMessage?: string; + + /** + * Custom placeholder for the input box. + * + * Default: `"Search"`. + */ + placeholder?: string; + + /** + * Prioritizes search results closer to a proximity point. + * The first matching rule in the array is used. + * Set to `null` to disable proximity. + * + * Default: `[ { type: "server-geolocation" } ]`. + */ + proximity?: ProximityRule[] | null; + + /** + * Activates reverse geocoding. + * + * Default: `false`. + */ + reverseActive?: boolean; + + /** + * Title of the reverse geocoding toggle button. + * + * Default: `"toggle reverse geocoding"`. + */ + reverseButtonTitle?: string; + + /** + * Excludes types for reverse geocoding. + * + * Default: Same as `excludeTypes`. + */ + reverseGeocodingExcludeTypes?: boolean; + + /** + * Limits results for reverse geocoding. + * Applied only if value is 1 or effective types contain a single value. + * + * See also `reverseGeocodingTypes` option. + * + * Default: The value of the `limit` option if set. If effective types contain a single value, the default is `1`. In all other cases, this option is not used. + */ + reverseGeocodingLimit?: number; + + /** + * Specifies types for reverse geocoding. + * + * If effective types are multiple values, the `limit`/`reverseGeocodingLimit` option is ignored. + * + * See also `reverseGeocodingLimit` option. + * + * Default: Same as `types`. + */ + reverseGeocodingTypes?: TypeRule[]; + + /** + * Automatically selects the first feature in the result list. + * + * Default: `true`. + */ + selectFirst?: boolean; + + /** + * Indicates when to show place/POI types in the dropdown: + * - `"never"`: Hide the type. + * - `"always"`: Always show the type. + * - `"if-needed"`: Show the type only if it cannot be determined from the icon. + * + * Default: `"if-needed"`. + */ + showPlaceType?: ShowPlaceType; + + /** + * Displays results while typing: + * - `false`: Search occurs only on pressing the Enter key. + * - `true`: Search begins when the input meets the `minLength` requirement. + * + * Default: `true`. + */ + showResultsWhileTyping?: boolean; + + /** + * Types to query, either as an array or `[minZoom, maxZoom, type]` format. + * `minZoom` is inclusive, `maxZoom` is exclusive, and either can be `null` or `undefined` for unbounded values. + * + * See `reverseGeocodingTypes` option for reverse geocoding types. + * + * Default: `undefined` (uses server default feature types). + */ + types?: TypeRule[]; +}; diff --git a/src/geocoder/geocoder.css b/src/geocoder/geocoder.css new file mode 100644 index 0000000..ce330d9 --- /dev/null +++ b/src/geocoder/geocoder.css @@ -0,0 +1,197 @@ +form { + font-family: "Open Sans", "Ubuntu", "Helvetica Neue", Arial, Helvetica, sans-serif; + position: relative; + background-color: #fff; + z-index: 10; + border-radius: 4px; + margin: 0; + padding: 2px; + transition: max-width 0.25s; + box-shadow: 0px 2px 5px rgba(51, 51, 89, 0.15); + --color-text: #444952; + --color-icon-button: #444952; + pointer-events: all; +} +form, +form *, +form *:after, +form *:before { + box-sizing: border-box; +} +form.can-collapse { + max-width: 33px; +} +form.can-collapse input::placeholder { + transition: opacity 0.25s; + opacity: 0; +} +form, +form:focus-within, +form:hover { + width: 270px; + max-width: 270px; +} +form input::placeholder, +form:focus-within input::placeholder, +form:hover input::placeholder { + opacity: 1; +} +input { + font: inherit; + font-size: 14px; + flex-grow: 1; + min-height: 29px; + background-color: transparent; + color: #444952; + white-space: nowrap; + overflow: hidden; + border: 0; + margin: 0; + padding: 0; +} +input:focus { + color: #444952; + outline: 0; + outline: none; + box-shadow: none; +} +ul, +div.error, +div.no-results { + background-color: #fff; + border-radius: 4px; + left: 0; + list-style: none; + margin: 0; + padding: 0; + position: absolute; + width: 100%; + top: calc(100% + 6px); + overflow: hidden; +} +ul { + font-size: 14px; + line-height: 16px; + box-shadow: 0px 5px 10px rgba(51, 51, 89, 0.15); +} +div.error, +div.no-results { + font: inherit; + line-height: 18px; + font-size: 12px; + display: flex; + gap: 16px; +} +div.error { + padding: 16px; + font-weight: 600; + color: #e25041; + background-color: #fbeae8; +} +div.error div { + flex-grow: 1; +} +div.error :global(svg) { + flex-shrink: 0; + width: 20px; + height: 20px; +} +div.error button { + flex-shrink: 0; +} +div.error button > :global(svg) { + width: 13px; + fill: #e25041; +} +div.error button:hover :global(svg), +div.error button:active :global(svg) { + fill: #444952; +} +div.no-results { + padding: 14px 24px 14px 16px; + font-weight: 400; + color: #6b7c93; + box-shadow: 0px 5px 10px rgba(51, 51, 89, 0.15); +} +div.no-results :global(svg) { + margin-top: 4px; + flex-shrink: 0; + width: 20px; + height: 20px; + width: 30px; + height: 30px; +} +:global(.leaflet-bottom) ul.options, +:global(.maplibregl-ctrl-bottom-left) ul.options, +:global(.maplibregl-ctrl-bottom-right) ul.options { + top: auto; + bottom: calc(100% + 6px); +} +button { + padding: 0; + margin: 0; + border: 0; + background-color: transparent; + height: auto; + width: auto; +} +button:hover { + background-color: transparent; +} +button:hover :global(svg), +button:active :global(svg) { + fill: #2b8bfb; +} +.input-group { + display: flex; + align-items: stretch; + gap: 7px; + padding-inline: 8px; + border-radius: 4px; + overflow: hidden; +} +.input-group:focus-within { + outline: #2b8bfb solid 2px; +} +.search-button { + flex-shrink: 0; +} +:global(.maplibregl-ctrl-geocoder:not(.maptiler-ctrl) .search-button svg) { + width: 12px !important; + transform: translate(0.5px, 0); +} +.clear-button-container { + display: flex; + display: none; + position: relative; + align-items: stretch; +} +.clear-button-container.displayable { + display: flex; + flex-shrink: 0; +} +:global(.maplibregl-ctrl-geocoder) { + position: relative; + z-index: 3; +} +:global(.maptiler-ctrl):not(:empty) { + box-shadow: none; +} +:global(.maptiler-ctrl) .input-group { + padding-inline: 8px; + border: white solid 2px; +} +:global(.maptiler-ctrl) .input-group:focus-within { + border: #2b8bfb solid 2px; + outline: 0; + outline: none; +} +:global(.maptiler-ctrl) form.can-collapse { + max-width: 33px; +} +:global(.maptiler-ctrl) form, +:global(.maptiler-ctrl) form:focus-within, +:global(.maptiler-ctrl) form:hover { + width: 270px; + max-width: 270px; +} diff --git a/src/geocoder/geocoder.ts b/src/geocoder/geocoder.ts new file mode 100644 index 0000000..9d21714 --- /dev/null +++ b/src/geocoder/geocoder.ts @@ -0,0 +1,808 @@ +import { convert } from "geo-coordinates-parser"; +import { LitElement, css, html, nothing, unsafeCSS } from "lit"; +import { customElement, property, query, state } from "lit/decorators.js"; +import { classMap } from "lit/directives/class-map.js"; +import { repeat } from "lit/directives/repeat.js"; + +import type { BBox, EnableReverse, Feature, FeatureCollection, ProximityRule, ShowPlaceType, TypeRule } from "../types"; +import { wrapNum } from "../utils/geo-utils"; +import { getProximity } from "../utils/proximity"; + +import "../components/clear-icon"; +import "../components/fail-icon"; +import "../components/loading-icon"; +import "../components/reverse-geocoding-icon"; +import "../components/search-icon"; +import "./geocoder-feature-item"; + +import type { MaptilerGeocoderEventName, MaptilerGeocoderEventNameMap } from "./geocoder-events"; +import type { MaptilerGeocoderOptions } from "./geocoder-options"; +import styles from "./geocoder.css?inline"; + +@customElement("maptiler-geocoder") +export class MaptilerGeocoderElement extends LitElement implements MaptilerGeocoderOptions { + static styles = css` + ${unsafeCSS(styles)} + `; + + @property({ attribute: false }) adjustUrl?: (url: URL) => void; + @property({ type: String }) apiKey?: string; + @property({ type: String }) apiUrl?: string; + @property({ type: Array }) bbox?: BBox; + @property({ type: String }) class?: string; + @property({ type: String }) clearButtonTitle?: string; + @property({ type: Boolean }) clearListOnPick: boolean = false; + @property({ type: Boolean }) clearOnBlur: boolean = false; + @property({ type: Boolean }) collapsed: boolean = false; + @property({ attribute: false }) country?: string | string[]; + @property({ type: Number }) debounceSearch?: number; + @property({ type: String }) enableReverse?: EnableReverse; + @property({ type: String }) errorMessage?: string; + @property({ type: Boolean }) excludeTypes: boolean = false; + @property({ type: Boolean }) exhaustiveReverseGeocoding: boolean = false; + @property({ type: Boolean }) fetchFullGeometryOnPick: boolean = false; + @property({ type: Object }) fetchParameters?: RequestInit; + @property({ attribute: false }) filter?: (feature: Feature) => boolean; + @property({ type: Object }) fuzzyMatch?: boolean | undefined; // type object because undefined is valid value + @property({ type: String }) iconsBaseUrl?: string; + @property({ type: Boolean }) keepListOpen: boolean = false; + @property({ attribute: false }) language?: string | string[] | null; + @property({ type: Number }) limit?: number; + @property({ type: Number }) minLength?: number; + @property({ type: String }) noResultsMessage?: string; + @property({ type: String }) placeholder?: string; + @property({ type: Array }) proximity?: ProximityRule[] | null; + @property({ type: Boolean }) reverseActive: boolean = false; + @property({ type: String }) reverseButtonTitle?: string; + @property({ type: Object }) reverseGeocodingExcludeTypes?: boolean | undefined; // type object because undefined is valid value + @property({ type: Number }) reverseGeocodingLimit?: number; + @property({ type: Array }) reverseGeocodingTypes?: TypeRule[]; + @property({ type: Object }) selectFirst?: boolean | undefined; // type object because undefined is valid value + @property({ type: String }) showPlaceType?: ShowPlaceType; + @property({ type: Object }) showResultsWhileTyping?: boolean | undefined; // type object because undefined is valid value + @property({ type: Array }) types?: TypeRule[]; + + @query("input") private input!: HTMLInputElement; + + @state() private searchValue: string = ""; + @state() private listFeatures?: Feature[]; + @state() private selectedItemIndex: number = -1; + @state() private picked?: Feature; + @state() private cachedFeatures: Feature[] = []; + @state() private lastSearchUrl: string = ""; + @state() private error: unknown; + @state() private abortController?: AbortController; // beware, this one is referenced in template + @state() private focused: boolean = false; + @state() private focusedDelayed: boolean = false; + + #isInitialized = false; + #wasFeatureListVisible = false; + #searchTimeoutRef?: number; + #missingIconsCache = new Set(); + #centerAndZoom: [zoom: number, lon: number, lat: number] | undefined; + + get #selected(): Feature | undefined { + return this.listFeatures?.[this.selectedItemIndex]; + } + get #isFeatureListVisible(): boolean { + return !!this.listFeatures?.length && (this.focusedDelayed || this.keepListOpen); + } + get #isLoading(): boolean { + return this.abortController !== undefined; + } + get #isSearchValueTooShort(): boolean { + return this.searchValue.length < (this.minLength ?? 2); + } + + protected firstUpdated() { + this.#isInitialized = true; + } + + setOptions(options: Partial) { + const elementOptions = { ...options }; + for (const prop of Object.keys(elementOptions) as Array) { + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + if (!propertyNames.includes(prop)) delete elementOptions[prop]; + } + Object.assign(this, elementOptions); + } + + /** + * Set the content of search input box. + * + * @param value text to set + */ + setQuery(value: string) { + this.#changeSearchValue(value); + this.#focusInputAndSelectText(); + } + + /** + * Set the content of search input box and immediately submit it. + * + * @param value text to set and submit + */ + submitQuery(value: string) { + this.#submitSearchValue(value); + } + + /** + * Clear search result list. + */ + clearList() { + this.#clearFeatures(); + this.picked = undefined; + this.selectedItemIndex = -1; + } + + /** + * Focus the search input box. + * + * @param options [FocusOptions](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus#options) + */ + override focus(options?: FocusOptions) { + this.input.focus(options); + } + + /** + * Blur the search input box. + */ + override blur() { + this.input.blur(); + } + + override addEventListener( + type: E, + listener: (this: HTMLElement, e: MaptilerGeocoderEventNameMap[E]) => unknown, + options?: boolean | AddEventListenerOptions, + ): void; + override addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void { + super.addEventListener(type, listener, options); + } + + override removeEventListener( + type: E, + listener: (this: HTMLElement, e: MaptilerGeocoderEventNameMap[E]) => unknown, + options?: boolean | EventListenerOptions, + ): void; + override removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void { + super.removeEventListener(type, listener, options); + } + + /** @internal */ + handleMapChange(centerAndZoom: [zoom: number, lon: number, lat: number] | undefined): void { + this.#centerAndZoom = centerAndZoom; + } + + /** @internal */ + handleMapClick(coordinates: [lng: number, lat: number]) { + if (this.reverseActive) { + this.#handleReverse(coordinates); + } + } + + #dispatch( + type: T, + ...[detail]: undefined extends MaptilerGeocoderEventNameMap[T]["detail"] ? [] : [detail: MaptilerGeocoderEventNameMap[T]["detail"]] + ): void { + if (!this.#isInitialized) return; + + this.dispatchEvent( + new CustomEvent(type, { + bubbles: true, + composed: true, + detail, + }), + ); + } + + #handleSubmit(event?: Event) { + event?.preventDefault(); + + this.focused = false; + + clearTimeout(this.#searchTimeoutRef); + + if (this.selectedItemIndex > -1 && this.listFeatures) { + this.picked = this.listFeatures[this.selectedItemIndex]; + + this.searchValue = this.picked.place_type[0] === "reverse" ? this.picked.place_name : this.picked.place_name.replace(/,.*/, ""); + + this.error = undefined; + + this.selectedItemIndex = -1; + } else if (this.searchValue) { + this.#search(this.searchValue, { exact: true }) + .then(() => { + this.picked = undefined; + }) + .catch((err: unknown) => (this.error = err)); + } + } + + #isQueryReverse(searchValue: string) { + try { + return convert(searchValue, 6); + } catch { + return false; + } + } + + #focusInputAndSelectText() { + setTimeout(() => { + this.input.focus(); + this.focused = true; + this.input.select(); + }); + } + + #changeSearchValue(searchValue: string) { + this.searchValue = searchValue; + this.#dispatch("querychange", { query: this.searchValue, reverseCoords: this.#isQueryReverse(searchValue) }); + + this.error = undefined; + this.picked = undefined; + + if (this.showResultsWhileTyping !== false) { + clearTimeout(this.#searchTimeoutRef); + + if (this.#isSearchValueTooShort) { + return; + } + + const sv = this.searchValue; + + this.#searchTimeoutRef = window.setTimeout(() => { + this.#search(sv).catch((err: unknown) => (this.error = err)); + }, this.debounceSearch ?? 200); + } else { + this.#clearFeatures(); + } + } + + #clearFeatures() { + if (this.listFeatures !== undefined) { + this.listFeatures = undefined; + this.#dispatch("featuresclear"); + } + } + + #submitSearchValue(searchValue: string) { + this.searchValue = searchValue; + this.#dispatch("querychange", { query: this.searchValue, reverseCoords: this.#isQueryReverse(searchValue) }); + + this.selectedItemIndex = -1; + this.#handleSubmit(); + } + + async #search(searchValue: string, { byId = false, exact = false }: undefined | { byId?: boolean; exact?: boolean } = {}) { + this.error = undefined; + + this.abortController?.abort(); + const ac = new AbortController(); + this.abortController = ac; + + try { + const apiUrl = this.apiUrl ?? import.meta.env.VITE_API_URL; + const isReverse = this.#isQueryReverse(searchValue); + + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + const urlObj = new URL(apiUrl + "/" + encodeURIComponent(isReverse ? `${isReverse.decimalLongitude},${isReverse.decimalLatitude}` : searchValue) + ".json"); + + const sp = urlObj.searchParams; + + if (this.language !== undefined) { + sp.set("language", Array.isArray(this.language) ? this.language.join(",") : (this.language ?? "")); + } + + // const [zoom] = mapController?.getCenterAndZoom() ?? []; + const zoom = undefined as number | undefined; + + let effTypes = (!isReverse || this.reverseGeocodingTypes === undefined ? this.types : this.reverseGeocodingTypes) + ?.map((typeRule) => + typeof typeRule === "string" ? typeRule : zoom === undefined || ((typeRule[0] ?? 0) <= zoom && zoom < (typeRule[1] ?? Infinity)) ? typeRule[2] : undefined, + ) + .filter((type) => type !== undefined); + + if (effTypes) { + effTypes = [...new Set(effTypes)]; + + sp.set("types", effTypes.join(",")); + } + + const effExcludeTypes = !isReverse || this.reverseGeocodingExcludeTypes === undefined ? this.excludeTypes : this.reverseGeocodingExcludeTypes; + + if (effExcludeTypes) { + sp.set("excludeTypes", String(effExcludeTypes)); + } + + if (this.bbox) { + sp.set("bbox", this.bbox.map((c) => c.toFixed(6)).join(",")); + } + + if (this.country) { + sp.set("country", Array.isArray(this.country) ? this.country.join(",") : this.country); + } + + if (!byId && !isReverse) { + const proximity = this.proximity ?? [{ type: "server-geolocation" }]; + const coords = await getProximity(this.#centerAndZoom, proximity, ac); + + if (coords) { + sp.set("proximity", coords); + } + + if (exact || this.showResultsWhileTyping === false) { + sp.set("autocomplete", "false"); + } + + sp.set("fuzzyMatch", String(this.fuzzyMatch !== false)); + } + + const limit = this.limit ?? 5; + const effReverseGeocodingLimit = this.reverseGeocodingLimit ?? limit; + + if (effReverseGeocodingLimit > 1 && effTypes?.length !== 1) { + console.warn("For reverse geocoding when limit > 1 then types must contain single value."); + } + + if (isReverse) { + if (effReverseGeocodingLimit === 1 || this.exhaustiveReverseGeocoding || effTypes?.length === 1) { + sp.set("limit", String(effReverseGeocodingLimit)); + } + // } else if (this.limit !== undefined) { + } else { + sp.set("limit", String(limit)); + } + + if (this.apiKey) { + sp.set("key", this.apiKey); + } + + this.adjustUrl?.(urlObj); + + const noTypes = urlObj.searchParams.get("types") === "" && urlObj.searchParams.get("excludeTypes") !== "true"; + + const url = urlObj.toString(); + + if (url === this.lastSearchUrl) { + if (byId) { + if (this.clearListOnPick) { + this.listFeatures = undefined; + // this.#dispatch("featuresclear"); + // this.#clearFeatures(); + } + + this.picked = this.cachedFeatures[0]; + } else { + this.listFeatures = this.cachedFeatures; + // this.#dispatch("featureslisted", { features: this.listFeatures }); + + if (this.listFeatures[this.selectedItemIndex]?.id !== this.#selected?.id) { + this.selectedItemIndex = -1; + } + } + + return; + } + + this.#dispatch("request", { urlObj }); + + this.lastSearchUrl = url; + + let featureCollection: FeatureCollection; + + if (noTypes) { + featureCollection = { type: "FeatureCollection", features: [] }; + } else { + const res = await fetch(url, { + signal: ac.signal, + ...this.fetchParameters, + }); + + if (!res.ok) { + throw new Error(await res.text()); + } + + featureCollection = (await res.json()) as FeatureCollection; + } + + this.#dispatch("response", { url, featureCollection }); + + if (byId) { + if (this.clearListOnPick) { + this.#clearFeatures(); + } + + this.picked = featureCollection.features[0]; + + this.cachedFeatures = [this.picked]; + } else { + this.listFeatures = featureCollection.features.filter(this.filter ?? (() => true)); + + if (isReverse) { + this.listFeatures.unshift({ + type: "Feature", + properties: {}, + /* eslint-disable @typescript-eslint/restrict-template-expressions */ + id: `reverse_${isReverse.decimalLongitude}_${isReverse.decimalLatitude}`, + text: `${isReverse.decimalLatitude}, ${isReverse.decimalLongitude}`, + place_name: `${isReverse.decimalLatitude}, ${isReverse.decimalLongitude}`, + /* eslint-enable @typescript-eslint/restrict-template-expressions */ + place_type: ["reverse"], + place_type_name: ["reverse"], + center: [isReverse.decimalLongitude, isReverse.decimalLatitude], + bbox: [isReverse.decimalLongitude, isReverse.decimalLatitude, isReverse.decimalLongitude, isReverse.decimalLatitude], + geometry: { + type: "Point", + coordinates: [isReverse.decimalLongitude, isReverse.decimalLatitude], + }, + }); + } + + this.#dispatch("featureslisted", { features: this.listFeatures }); + + this.cachedFeatures = this.listFeatures; + + if (this.listFeatures[this.selectedItemIndex]?.id !== this.#selected?.id) { + this.selectedItemIndex = -1; + } + + if (isReverse) { + this.input.focus(); + } + } + } catch (e: unknown) { + if (e && typeof e === "object" && "name" in e && e.name === "AbortError") { + return; + } + + throw e; + } finally { + if (ac === this.abortController) { + this.abortController = undefined; + } + } + } + + #handleReverse(coordinates: [lng: number, lat: number]) { + this.reverseActive = this.enableReverse === "always"; + + this.#clearFeatures(); + this.picked = undefined; + + this.#submitSearchValue(`${coordinates[1].toFixed(6)}, ${wrapNum(coordinates[0], [-180, 180], true).toFixed(6)}`); + this.#focusInputAndSelectText(); + } + + #handleKeyDown(e: KeyboardEvent) { + if (!this.listFeatures) { + return; + } + + const dir = e.key === "ArrowDown" ? 1 : e.key === "ArrowUp" ? -1 : 0; + + if (!dir) { + return; + } + + this.input.focus(); + + this.focused = true; + + e.preventDefault(); + + if (this.picked && this.selectedItemIndex === -1) { + this.selectedItemIndex = this.listFeatures.findIndex((listFeature) => listFeature.id === this.picked?.id); + } + + if (this.selectedItemIndex === (this.picked || this.selectFirst !== false ? 0 : -1) && dir === -1) { + this.selectedItemIndex = this.listFeatures.length; + } + + this.selectedItemIndex += dir; + + if (this.selectedItemIndex >= this.listFeatures.length) { + this.selectedItemIndex = -1; + } + + if (this.selectedItemIndex < 0 && (this.picked || this.selectFirst !== false)) { + this.selectedItemIndex = 0; + } + } + + #handleInput(event: InputEvent & { target: HTMLInputElement }) { + this.#changeSearchValue(event.target.value); + } + + #pick(feature: Feature) { + if (!this.picked || this.picked.id !== feature.id) { + this.picked = feature; + this.searchValue = feature.place_name; + } + } + + #handleMouseEnter(index: number) { + this.selectedItemIndex = index; + } + + #handleMouseLeave() { + if (!this.selectFirst !== false || this.picked) { + this.selectedItemIndex = -1; + } + + // // re-focus on picked + // if (this.flyToSelected) { + // this.#goToPicked(); + // } + } + + #handleClear() { + this.searchValue = ""; + this.#dispatch("queryclear"); + + this.picked = undefined; + this.input.focus(); + } + + willUpdate(changedProperties: Map) { + if (changedProperties.has("error") && this.error) { + console.error("Error from geocoding component", this.error); + } + + if (changedProperties.has("enableReverse")) { + this.reverseActive = this.enableReverse === "always"; + } + + // @TODO is this needed or is it handled by a different piece of code?? + if (["picked"].some((prop) => changedProperties.has(prop))) { + if (this.picked) { + if (this.clearListOnPick) { + this.#clearFeatures(); + } + + // this.markedFeatures = undefined; + this.selectedItemIndex = -1; + } + } + + // if (["markedFeatures", "listFeatures"].some((prop) => changedProperties.has(prop)) && this.markedFeatures !== this.listFeatures) { + // this.markedFeatures = undefined; + // } + + if (["searchValue", "minLength"].some((prop) => changedProperties.has(prop)) && this.#isSearchValueTooShort) { + this.#clearFeatures(); + this.error = undefined; + } + + if (["focused"].some((prop) => changedProperties.has(prop))) { + setTimeout(() => { + this.focusedDelayed = this.focused; + }, 100); + } + + // close dropdown in the next cycle so that the selected item event has the chance to fire + if (["focused"].some((prop) => changedProperties.has(prop))) { + setTimeout(() => { + if (this.clearOnBlur && !this.focused) { + this.searchValue = ""; + } + }, 100); + } + + if ( + ["selectFirst", "listFeatures", "selectedItemIndex", "picked"].some((prop) => changedProperties.has(prop)) && + this.selectFirst !== false && + this.listFeatures?.length && + this.selectedItemIndex == -1 && + !this.picked + ) { + this.selectedItemIndex = 0; + } + + // if (["searchValue"].some((prop) => changedProperties.has(prop))) { + // this.#dispatch("querychange", { query: this.searchValue }); + // } + + // if (["listFeatures"].some((prop) => changedProperties.has(prop))) { + // this.#dispatch("featureslisted", { features: this.listFeatures }); + // } + + if (["listFeatures", "selectedItemIndex"].some((prop) => changedProperties.has(prop))) { + this.#dispatch("select", { feature: this.#selected }); + } + + if (["picked"].some((prop) => changedProperties.has(prop))) { + if (this.picked) { + (this.fetchFullGeometryOnPick && !this.picked.address && this.picked.geometry.type === "Point" && this.picked.place_type[0] !== "reverse" + ? this.#search(this.picked.id, { byId: true }) + : Promise.resolve() + ).then( + () => { + this.#dispatch("pick", { feature: this.picked }); + }, + (e: unknown) => { + if (e && typeof e === "object" && "name" in e && e.name === "AbortError") return; + this.error = e; + this.#dispatch("pick", { feature: this.picked }); + }, + ); + } + } + + if (["listFeatures", "focusedDelayed"].some((prop) => changedProperties.has(prop))) { + if (this.#isFeatureListVisible) { + this.#dispatch("featuresshow"); + this.#wasFeatureListVisible = true; + } else if (this.#wasFeatureListVisible) { + this.#dispatch("featureshide"); + } + } + + // if (["markedFeatures"].some((prop) => changedProperties.has(prop))) { + // this.#dispatch("featuresmarked", { features: this.markedFeatures }); + // } + + if (["reverseActive"].some((prop) => changedProperties.has(prop))) { + this.#dispatch("reversetoggle", { reverse: this.reverseActive }); + } + + // if (["reverseActive"].some((prop) => changedProperties.has(prop)) && mapController) { + // mapController.indicateReverse(this.reverseActive); + // } + } + + render() { + /* eslint-disable @typescript-eslint/unbound-method */ + return html` +
    +
    + + + (this.focused = true)} + @blur=${() => (this.focused = false)} + @click=${() => (this.focused = true)} + @keydown=${this.#handleKeyDown} + @input=${this.#handleInput} + @change=${() => (this.picked = undefined)} + placeholder=${this.placeholder ?? "Search"} + aria-label=${this.placeholder ?? "Search"} + /> + +
    + ${!this.#isLoading + ? html` + + ` + : html``} +
    + + ${this.enableReverse === "button" + ? html` + + ` + : nothing} + + +
    + + ${this.error + ? html` +
    + + +
    ${this.errorMessage ?? "Something went wrong…"}
    +
    ${this.error}
    + + +
    + ` + : (!this.focusedDelayed && !this.keepListOpen) || this.listFeatures === undefined + ? nothing + : this.listFeatures.length === 0 + ? html` +
    + + +
    + ${this.noResultsMessage ?? + "Oops! Looks like you're trying to predict something that's not quite right. We can't seem to find what you're looking for. Maybe try double-checking your spelling or try a different search term. Keep on typing - we'll do our best to get you where you need to go!"} +
    +
    + ` + : html` +
      + ${repeat( + this.listFeatures, + (feature) => feature.id + (feature.address ? "," + feature.address : ""), + (feature, i) => html` + { + this.#handleMouseEnter(i); + }} + @select=${() => { + this.#pick(feature); + }} + .missingIconsCache=${this.#missingIconsCache} + .iconsBaseUrl=${this.iconsBaseUrl ?? `https://cdn.maptiler.com/maptiler-geocoding-control/v${import.meta.env.VITE_LIB_VERSION}/icons/`} + > + ${feature.place_name} + + `, + )} +
    + `} +
    + `; + /* eslint-enable @typescript-eslint/unbound-method */ + } +} + +declare global { + interface HTMLElementTagNameMap { + "maptiler-geocoder": MaptilerGeocoderElement; + } +} + +const propertyNames = [ + "adjustUrl", + "apiKey", + "apiUrl", + "bbox", + "class", + "clearButtonTitle", + "clearListOnPick", + "clearOnBlur", + "collapsed", + "country", + "debounceSearch", + "enableReverse", + "errorMessage", + "excludeTypes", + "reverseGeocodingExcludeTypes", + "exhaustiveReverseGeocoding", + "fetchParameters", + "fetchFullGeometryOnPick", + "filter", + "fuzzyMatch", + "iconsBaseUrl", + "keepListOpen", + "language", + "limit", + "reverseGeocodingLimit", + "minLength", + "noResultsMessage", + "placeholder", + "proximity", + "reverseActive", + "reverseButtonTitle", + "selectFirst", + "showPlaceType", + "showResultsWhileTyping", + "types", + "reverseGeocodingTypes", +] as const satisfies readonly (keyof MaptilerGeocoderOptions)[]; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..194b9c6 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,9 @@ +export * from "./components/clear-icon"; +export * from "./components/fail-icon"; +export * from "./components/loading-icon"; +export * from "./components/reverse-geocoding-icon"; +export * from "./components/search-icon"; +export * from "./geocoder/geocoder"; +export * from "./geocoder/geocoder-events"; +export * from "./geocoder/geocoder-options"; +export * from "./types"; diff --git a/src/leaflet-controller.ts b/src/leaflet-controller.ts deleted file mode 100644 index 560ef73..0000000 --- a/src/leaflet-controller.ts +++ /dev/null @@ -1,399 +0,0 @@ -import bbox from "@turf/bbox"; -import clone from "@turf/clone"; -import { feature, featureCollection } from "@turf/helpers"; -import union from "@turf/union"; -import type { - FeatureCollection, - GeoJSON, - Position as GPosition, - LineString, - MultiLineString, - MultiPolygon, - Polygon, -} from "geojson"; -import * as L from "leaflet"; -import { unwrapBbox } from "./geoUtils"; -import MarkerIcon from "./MarkerIcon.svelte"; -import { setMask } from "./mask"; -import type { BBox, Feature, MapController, MapEvent, Position } from "./types"; - -const defaultFullGeometryStyle: L.StyleFunction = (feature) => { - const type = feature?.geometry?.type; - - const weight = feature?.properties?.isMask - ? 0 - : type === "LineString" || type === "MultiLineString" - ? 3 - : 2; - - return { - color: "#3170fe", - fillColor: "#000", - fillOpacity: feature?.properties?.isMask ? 0.1 : 0, - weight, - dashArray: [weight, weight], - lineCap: "butt", - }; -}; - -export function createLeafletMapController( - map: L.Map, - marker: - | boolean - | null - | L.MarkerOptions - | ((map: L.Map, feature?: Feature) => L.Marker | undefined | null) = true, - showResultMarkers: - | boolean - | null - | L.MarkerOptions - | ((map: L.Map, feature: Feature) => L.Marker | undefined | null) = true, - flyToOptions: L.ZoomPanOptions | null = {}, - flyToBounds: L.FitBoundsOptions | null = {}, - fullGeometryStyle: - | null - | boolean - | L.PathOptions - | L.StyleFunction = defaultFullGeometryStyle, -) { - let eventHandler: ((e: MapEvent) => void) | undefined; - - const markers: L.Marker[] = []; - - let selectedMarker: L.Marker | undefined; - - let reverseMarker: L.Marker | undefined; - - const resultLayer = L.geoJSON(undefined, { - style: - fullGeometryStyle === true - ? defaultFullGeometryStyle - : fullGeometryStyle === false - ? undefined - : (fullGeometryStyle ?? undefined), - interactive: false, - }).addTo(map); - - const handleMapClick = (e: L.LeafletMouseEvent) => { - eventHandler?.({ - type: "mapClick", - coordinates: [e.latlng.lng, e.latlng.lat], - }); - }; - - function createMarker(pos: L.LatLngExpression, interactive = false) { - const element = document.createElement("div"); - - new MarkerIcon({ props: { displayIn: "leaflet" }, target: element }); - - return new L.Marker(pos, { - interactive, - icon: new L.DivIcon({ - html: element, - className: "", - iconAnchor: [12, 26], - iconSize: [25, 30], - tooltipAnchor: [1, -24], - }), - }); - } - - return { - setEventHandler(handler: undefined | ((e: MapEvent) => void)): void { - if (handler) { - eventHandler = handler; - - map.on("click", handleMapClick); - } else { - eventHandler = undefined; - - map.off("click", handleMapClick); - } - }, - - flyTo(center: Position, zoom?: number) { - map.flyTo([center[1], center[0]], zoom, { duration: 2, ...flyToOptions }); - }, - - fitBounds(bbox: BBox, padding: number, maxZoom?: number): void { - map.flyToBounds( - [ - [bbox[1], bbox[0]], - [bbox[3], bbox[2]], - ], - { - padding: [padding, padding], - duration: 2, - ...(maxZoom ? { maxZoom } : {}), - ...flyToBounds, - }, - ); - }, - - indicateReverse(reverse: boolean): void { - map.getContainer().style.cursor = reverse ? "crosshair" : ""; - }, - - setReverseMarker(coordinates?: Position) { - if (!marker) { - return; - } - - const latLng = - coordinates && ([coordinates[1], coordinates[0]] as Position); - - if (reverseMarker) { - if (!latLng) { - reverseMarker.remove(); - - reverseMarker = undefined; - } else { - reverseMarker.setLatLng(latLng); - } - } else if (latLng) { - if (marker instanceof Function) { - reverseMarker = marker(map) ?? undefined; - } else { - reverseMarker = ( - typeof marker === "object" - ? new L.Marker(latLng, marker) - : createMarker(latLng) - ).addTo(map); - - reverseMarker.getElement()?.classList.add("marker-reverse"); - } - } - }, - - setFeatures( - markedFeatures: Feature[] | undefined, - picked: Feature | undefined, - showPolygonMarker: boolean, - ): void { - function setData(data?: GeoJSON) { - resultLayer.clearLayers(); - - if (data) { - resultLayer.addData(data); - } - } - - for (const marker of markers) { - marker.remove(); - } - - markers.length = 0; - - setData(); - - block: if (picked) { - let handled = false; - - if (picked.geometry.type === "GeometryCollection") { - const geoms = picked.geometry.geometries.filter( - (geometry): geometry is Polygon | MultiPolygon => - geometry.type === "Polygon" || geometry.type === "MultiPolygon", - ); - - ok: if (geoms.length > 0) { - const unioned = union( - featureCollection(geoms.map((geom) => feature(geom))), - ); - - if (!unioned) { - break ok; - } - - setMask( - { - ...picked, - geometry: unioned.geometry, - }, - setData, - ); - - handled = true; - } else { - const geometries = picked.geometry.geometries.filter( - (geometry): geometry is LineString | MultiLineString => - geometry.type === "LineString" || - geometry.type === "MultiLineString", - ); - - if (geometries.length > 0) { - setData({ - ...picked, - geometry: { type: "GeometryCollection", geometries }, - }); - - handled = true; - } - } - } - - if (handled) { - // nothing - } else if ( - picked.geometry.type === "Polygon" || - picked.geometry.type === "MultiPolygon" - ) { - setMask(picked as Feature, (fc) => { - if (!fc) { - return; - } - - // leaflet doesn't repeat features every 360 degrees along longitude - // so we clone it manually to the direction(s) - // which could be displayed when auto-zoomed on the feature - - const features = [...fc.features]; - - const bb = unwrapBbox(bbox(picked) as BBox); - - const span = bb[2] - bb[0]; - - if (bb[0] - span / 4 < -180) { - features.push(...shiftPolyCollection(fc, -360).features); - } - - if (bb[2] + span / 4 > 180) { - features.push(...shiftPolyCollection(fc, 360).features); - } - - setData(featureCollection(features)); - }); - } else if ( - picked.geometry.type === "LineString" || - picked.geometry.type === "MultiLineString" - ) { - setData(picked); - - break block; // no pin for (multi)linestrings - } - - if (!showPolygonMarker && !picked.geometry.type.endsWith("Point")) { - break block; - } - - if (marker instanceof Function) { - const m = marker(map, picked); - - if (m) { - markers.push(m.addTo(map)); - } - } else if (marker) { - const pos: L.LatLngExpression = [picked.center[1], picked.center[0]]; - - markers.push( - typeof marker === "object" - ? new L.Marker(pos, marker) - : createMarker(pos).addTo(map), - ); - } - } - - if (showResultMarkers) { - for (const feature of markedFeatures ?? []) { - if (feature === picked) { - continue; - } - - const pos: L.LatLngExpression = [ - feature.center[1], - feature.center[0], - ]; - - let marker; - - if (showResultMarkers instanceof Function) { - marker = showResultMarkers(map, feature); - - if (!marker) { - continue; - } - } else { - marker = ( - typeof showResultMarkers === "object" - ? new L.Marker(pos, showResultMarkers) - : createMarker(pos, true) - ) - .addTo(map) - .bindTooltip( - feature.place_type[0] === "reverse" - ? feature.place_name - : feature.place_name.replace(/,.*/, ""), - { - direction: "top", - }, - ); - } - - const element = marker.getElement(); - - if (element) { - element.addEventListener("click", (e) => { - e.stopPropagation(); - - eventHandler?.({ type: "markerClick", id: feature.id }); - }); - - element.addEventListener("mouseenter", () => { - eventHandler?.({ type: "markerMouseEnter", id: feature.id }); - }); - - element.addEventListener("mouseleave", () => { - eventHandler?.({ type: "markerMouseLeave", id: feature.id }); - }); - - element.classList.toggle("marker-fuzzy", !!feature.matching_text); - } - - markers.push(marker); - } - } - }, - - setSelectedMarker(index: number): void { - if (selectedMarker) { - selectedMarker.getElement()?.classList.toggle("marker-selected", false); - } - - selectedMarker = index > -1 ? markers[index] : undefined; - - selectedMarker?.getElement()?.classList.toggle("marker-selected", true); - }, - - getCenterAndZoom() { - const c = map.getCenter(); - - return [map.getZoom(), c.lng, c.lat]; - }, - } satisfies MapController; -} - -function shiftPolyCollection( - featureCollection: FeatureCollection, - distance: number, -): FeatureCollection { - const cloned = clone(featureCollection); - - for (const feature of cloned.features) { - if (feature.geometry.type == "MultiPolygon") { - for (const poly of feature.geometry.coordinates) { - shiftPolyCoords(poly, distance); - } - } else { - shiftPolyCoords(feature.geometry.coordinates, distance); - } - } - - return cloned; -} - -function shiftPolyCoords(coordinates: GPosition[][], distance: number) { - for (const ring of coordinates) { - for (const position of ring) { - position[0] += distance; - } - } -} diff --git a/src/leaflet.ts b/src/leaflet.ts deleted file mode 100644 index ad75338..0000000 --- a/src/leaflet.ts +++ /dev/null @@ -1,307 +0,0 @@ -import * as L from "leaflet"; -import GeocodingControlComponent from "./GeocodingControl.svelte"; -import { createLeafletMapController } from "./leaflet-controller"; -import type { ControlOptions, DispatcherType, Feature } from "./types"; -export { createLeafletMapController } from "./leaflet-controller"; - -type LeafletControlOptions = ControlOptions & - L.ControlOptions & { - /** - * Marker to be added to the map at the location of the user-selected result using a default set of Marker options. - * - * - If `true` or `undefined` then a default marker will be used.\ - * - If the value is [MarkerOptions](https://leafletjs.com/reference.html#marker-option) then the marker will be constructed using these options. - * - If the value is a function then it can create and configure custom [Marker](https://leafletjs.com/reference.html#marker), - * add it to the [Map](https://leafletjs.com/reference.html#map) and return it. - * Function accepts [Map](https://leafletjs.com/reference.html#map) and `Feature` as parameters. - * Feature is `undefined` for the reverse location marker. - * - If `false` or `null` then no marker will be added to the map. - * - * Default value is `true`. - */ - marker?: - | null - | boolean - | L.MarkerOptions - | ((map: L.Map, feature?: Feature) => L.Marker | undefined | null); - - /** - * Marker be added to the map at the location the geocoding results. - * - * - If `true` or `undefined` then a default marker will be used. - * - If the value is [MarkerOptions](https://leafletjs.com/reference.html#marker-option) then the marker will be constructed using these options. - * - If the value is a function then it can create and configure custom [Marker](https://leafletjs.com/reference.html#marker), - * add it to the [Map](https://leafletjs.com/reference.html#map) and return it. - * In this case the default pop-up won't be added to the marker. - * Function accepts [Map](https://leafletjs.com/reference.html#map) and `Feature` as parameters. - * - If `false` or `null` then no marker will be added to the map. - * - * Default value is `true`. - */ - showResultMarkers?: - | null - | boolean - | L.MarkerOptions - | ((map: L.Map, feature: Feature) => L.Marker | undefined | null); - - /** - * Animation to selected feature on the map. - * - * - If `false` or `null` then animating the map to a selected result is disabled. - * - If `true` or `undefined` then animating the map will use the default animation parameters. - * - If an [ZoomPanOptions](https://leafletjs.com/reference.html#zoom/pan-options) - * ` & `[FitBoundsOptions](https://leafletjs.com/reference.html#fitbounds-options) then it will be passed as options - * to the map [flyTo](https://leafletjs.com/reference.html#map-flyto) - * or [fitBounds](https://leafletjs.com/reference.html#map-fitbounds) method providing control over the animation of the transition. - * - * Default value is `true`. - */ - flyTo?: null | boolean | (L.ZoomPanOptions & L.FitBoundsOptions); - - /** - * Style for the full feature geometry. - * - * - If `false` or `null` then no full geometry is drawn. - * - If `true` or `undefined` then default-styled full geometry is drawn. - * - If an [PathOptions](https://leafletjs.com/reference.html#path-option) then it will be used to style the full geometry. - * - If a function accepting a `Feature` and returning [PathOptions](https://leafletjs.com/reference.html#path-option) - * then it must teturn the style and will be used to style the full geometry. - */ - fullGeometryStyle?: null | boolean | L.PathOptions | L.StyleFunction; - }; - -type LeafletEvent = { - type: T; - target: GeocodingControl; - sourceTarget: GeocodingControl; -}; - -type CustomEventMap = { - [T in keyof DispatcherType]: DispatcherType[T] & LeafletEvent; -}; - -/** - * Leaflet mixins https://leafletjs.com/reference.html#class - * for TypeScript https://www.typescriptlang.org/docs/handbook/mixins.html - * @internal - */ -// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging -class EventedControl extends L.Control {} - -// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging -interface EventedControl extends L.Control { - on( - type: T, - fn: (event: CustomEventMap[T]) => void, - context?: unknown, - ): this; - - addEventListener( - type: T, - fn: (event: CustomEventMap[T]) => void, - context?: unknown, - ): this; - - once( - type: T, - fn: (event: CustomEventMap[T]) => void, - context?: unknown, - ): this; - - addOneTimeEventListener( - type: T, - fn: (event: CustomEventMap[T]) => void, - context?: unknown, - ): this; - - off( - type?: T, - fn?: (event: CustomEventMap[T]) => void, - context?: unknown, - ): this; - - off(eventMap?: { - [T in keyof CustomEventMap]?: (event: CustomEventMap[T]) => void; - }): this; - - removeEventListener( - type?: T, - fn?: (event: CustomEventMap[T]) => void, - context?: unknown, - ): this; - - listens( - type: T, - fn: (event: CustomEventMap[T]) => void, - context?: unknown, - propagate?: boolean, - ): boolean; - - fire(type: string, data?: unknown, propagate?: boolean): this; - - addEventParent(obj: L.Evented): this; - - removeEventParent(obj: L.Evented): this; - - fireEvent(type: string, data?: unknown, propagate?: boolean): this; - - hasEventListeners(type: T): boolean; -} - -L.Util.extend(EventedControl.prototype, L.Evented.prototype); - -export class GeocodingControl extends EventedControl { - #gc?: GeocodingControlComponent; - - #options: LeafletControlOptions; - - constructor(options: LeafletControlOptions) { - super(options); - - this.#options = options; - } - - onAdd(map: L.Map) { - const div = document.createElement("div"); - - div.className = "leaflet-ctrl-geocoder"; - - L.DomEvent.disableClickPropagation(div); - - L.DomEvent.disableScrollPropagation(div); - - const { - marker, - showResultMarkers, - flyTo, - fullGeometryStyle, - position, - ...restOptions - } = this.#options; - - const flyToOptions = typeof flyTo === "boolean" ? {} : flyTo; - - const mapController = createLeafletMapController( - map, - marker, - showResultMarkers, - flyToOptions, - flyToOptions, - fullGeometryStyle, - ); - - this.#gc = new GeocodingControlComponent({ - target: div, - props: { - mapController, - flyTo: flyTo === undefined ? true : !!flyTo, - ...restOptions, - }, - }); - - const eventNames: Record = { - select: undefined, - pick: undefined, - featureslisted: undefined, - featuresmarked: undefined, - response: undefined, - optionsvisibilitychange: undefined, - reversetoggle: undefined, - querychange: undefined, - }; - - for (const eventName in eventNames) { - this.#gc.$on(eventName, (event) => this.fire(eventName, event.detail)); - } - - return div; - } - - /** - * Update the control options. - * - * @param options options to update - */ - setOptions(options: LeafletControlOptions) { - Object.assign(this.#options, options); - - const { - marker, - showResultMarkers, - flyTo, - fullGeometryStyle, - ...restOptions - } = this.#options; - - this.#gc?.$set(restOptions); - } - - /** - * Set the content of search input box. - * - * @param value text to set - * @param submit perform the search - */ - setQuery(value: string, submit = true) { - this.#gc?.setQuery(value, submit); - } - - /** - * Clear geocoding search results from the map. - */ - clearMap() { - this.#gc?.clearMap(); - } - - /** - * Clear search result list. - */ - clearList() { - this.#gc?.clearList(); - } - - /** - * Set reverse geocoding mode. - * - * @param reverseActive reverse geocoding active - */ - setReverseMode(reverseActive: boolean) { - this.#gc?.$set({ reverseActive }); - } - - /** - * Focus the search input box. - * - * @param options [FocusOptions](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus#options) - */ - focus(options?: FocusOptions) { - this.#gc?.focus(options); - } - - /** - * Blur the search input box. - */ - blur() { - this.#gc?.blur(); - } - - onRemove() { - this.#gc?.$destroy(); - } -} - -function createControl( - ...params: ConstructorParameters -) { - return new GeocodingControl(...params); -} - -if ( - window.L && - typeof window.L === "object" && - typeof window.L.control === "function" -) { - ( - window.L.control as unknown as { maptilerGeocoding: typeof createControl } - ).maptilerGeocoding = createControl; -} diff --git a/src/maplibregl-controller.ts b/src/maplibregl-controller.ts deleted file mode 100644 index 271cda5..0000000 --- a/src/maplibregl-controller.ts +++ /dev/null @@ -1,415 +0,0 @@ -import { feature, featureCollection } from "@turf/helpers"; -import union from "@turf/union"; -import type { - GeoJSON, - LineString, - MultiLineString, - MultiPolygon, - Polygon, -} from "geojson"; -import type * as maplibregl from "maplibre-gl"; -import type { - FillLayerSpecification, - FitBoundsOptions, - FlyToOptions, - GeoJSONSource, - LineLayerSpecification, - Map, - MapMouseEvent, - Marker, - MarkerOptions, -} from "maplibre-gl"; -import MarkerIcon from "./MarkerIcon.svelte"; -import { setMask } from "./mask"; -import type { BBox, Position } from "./types"; -import type { Feature, MapController, MapEvent } from "./types.js"; - -export type MapLibreGL = Pick; - -export type FullGeometryStyle = { - fill: Pick; - line: Pick; -}; - -const defaultGeometryStyle: FullGeometryStyle = { - fill: { - paint: { - "fill-color": "#000", - "fill-opacity": 0.1, - }, - filter: ["all", ["==", ["geometry-type"], "Polygon"], ["has", "isMask"]], - }, - line: { - layout: { - "line-cap": "square", - }, - paint: { - "line-width": ["case", ["==", ["geometry-type"], "Polygon"], 2, 3], - "line-dasharray": [1, 1], - "line-color": "#3170fe", - }, - filter: ["!", ["has", "isMask"]], - }, -}; - -const RESULT_SOURCE = "mtlr-gc-full-geom"; - -const RESULT_LAYER_FILL = "mtlr-gc-full-geom-fill"; - -const RESULT_LAYER_LINE = "mtlr-gc-full-geom-line"; - -export function createMapLibreGlMapController( - map: Map, - maplibregl?: MapLibreGL | undefined, - marker: - | boolean - | null - | MarkerOptions - | ((map: Map, feature?: Feature) => Marker | undefined | null) = true, - showResultMarkers: - | boolean - | null - | MarkerOptions - | ((map: Map, feature: Feature) => Marker | undefined | null) = true, - flyToOptions: FlyToOptions | null = {}, - fitBoundsOptions: FitBoundsOptions | null = {}, - fullGeometryStyle: boolean | null | FullGeometryStyle = defaultGeometryStyle, -) { - let eventHandler: ((e: MapEvent) => void) | undefined; - - const markers: Marker[] = []; - - let selectedMarker: maplibregl.Marker | undefined; - - let reverseMarker: maplibregl.Marker | undefined; - - let savedData: GeoJSON | undefined; // used to restore features on style switch - - function syncFullGeometryLayer() { - if (!map.loaded) { - map.once("load", syncFullGeometryLayer); - - return; - } - - const effFullGeometryStyle = !fullGeometryStyle - ? undefined - : fullGeometryStyle === true - ? defaultGeometryStyle - : fullGeometryStyle; - - if (!effFullGeometryStyle?.fill && !effFullGeometryStyle?.line) { - return; - } - - const source = map.getSource(RESULT_SOURCE); - - if (source) { - source.setData(savedData ?? featureCollection([])); - } else if (savedData) { - map.addSource(RESULT_SOURCE, { - type: "geojson", - data: savedData, - }); - } else { - return; - } - - if (!map.getLayer(RESULT_LAYER_FILL) && effFullGeometryStyle?.fill) { - map.addLayer({ - ...effFullGeometryStyle?.fill, - id: RESULT_LAYER_FILL, - type: "fill", - source: RESULT_SOURCE, - }); - } - - if (!map.getLayer(RESULT_LAYER_LINE) && effFullGeometryStyle?.line) { - map.addLayer({ - ...effFullGeometryStyle?.line, - id: RESULT_LAYER_LINE, - type: "line", - source: RESULT_SOURCE, - }); - } - } - - function setAndSaveData(data?: GeoJSON) { - savedData = data; - - syncFullGeometryLayer(); - } - - map.on("styledata", () => { - // timeout prevents collision with svelte-maplibre library - setTimeout(() => { - if (savedData) { - syncFullGeometryLayer(); - } - }); - }); - - const handleMapClick = (e: MapMouseEvent) => { - eventHandler?.({ - type: "mapClick", - coordinates: [e.lngLat.lng, e.lngLat.lat], - }); - }; - - function createMarker(interactive = false) { - if (!maplibregl) { - throw new Error(); - } - - const element = document.createElement("div"); - - if (interactive) { - element.classList.add("marker-interactive"); - } - - new MarkerIcon({ - props: { displayIn: "maplibre" }, - target: element, - }); - - return new maplibregl.Marker({ element, offset: [1, -13] }); - } - - return { - setEventHandler(handler: undefined | ((e: MapEvent) => void)): void { - if (handler) { - eventHandler = handler; - - map.on("click", handleMapClick); - } else { - eventHandler = undefined; - - map.off("click", handleMapClick); - } - }, - - flyTo(center: Position, zoom?: number): void { - map.flyTo({ center, ...(zoom ? { zoom } : {}), ...flyToOptions }); - }, - - fitBounds(bbox: BBox, padding: number, maxZoom?: number): void { - map.fitBounds( - [ - [bbox[0], bbox[1]], - [bbox[2], bbox[3]], - ], - { padding, ...(maxZoom ? { maxZoom } : {}), ...fitBoundsOptions }, - ); - }, - - indicateReverse(reverse: boolean): void { - map.getCanvasContainer().style.cursor = reverse ? "crosshair" : ""; - }, - - setReverseMarker(coordinates?: Position) { - if (!maplibregl || !marker) { - return; - } - - if (reverseMarker) { - if (!coordinates) { - reverseMarker.remove(); - - reverseMarker = undefined; - } else { - reverseMarker.setLngLat(coordinates); - } - } else if (coordinates) { - if (marker instanceof Function) { - reverseMarker = marker(map) ?? undefined; - } else { - reverseMarker = ( - typeof marker === "object" - ? new maplibregl.Marker(marker) - : createMarker() - ) - .setLngLat(coordinates) - .addTo(map); - - reverseMarker.getElement().classList.add("marker-reverse"); - } - } - }, - - setFeatures( - markedFeatures: Feature[] | undefined, - picked: Feature | undefined, - showPolygonMarker: boolean, - ): void { - for (const marker of markers) { - marker.remove(); - } - - markers.length = 0; - - setAndSaveData(undefined); - - if (!maplibregl) { - return; - } - - block: if (picked) { - let handled = false; - - if (picked.geometry.type === "GeometryCollection") { - const geoms = picked.geometry.geometries.filter( - (geometry): geometry is Polygon | MultiPolygon => - geometry.type === "Polygon" || geometry.type === "MultiPolygon", - ); - - ok: if (geoms.length > 0) { - const unioned = union( - featureCollection(geoms.map((geom) => feature(geom))), - ); - - if (!unioned) { - break ok; - } - - setMask( - { - ...picked, - geometry: unioned.geometry, - }, - setAndSaveData, - ); - - handled = true; - } else { - const geometries = picked.geometry.geometries.filter( - (geometry): geometry is LineString | MultiLineString => - geometry.type === "LineString" || - geometry.type === "MultiLineString", - ); - - if (geometries.length > 0) { - setAndSaveData({ - ...picked, - geometry: { type: "GeometryCollection", geometries }, - }); - - handled = true; - } - } - } - - if (handled) { - // nothing - } else if ( - picked.geometry.type === "Polygon" || - picked.geometry.type === "MultiPolygon" - ) { - setMask(picked as Feature, setAndSaveData); - } else if ( - picked.geometry.type === "LineString" || - picked.geometry.type === "MultiLineString" - ) { - setAndSaveData(picked); - - break block; // no pin for (multi)linestrings - } - - if (!showPolygonMarker && !picked.geometry.type.endsWith("Point")) { - break block; - } - - if (marker instanceof Function) { - const m = marker(map, picked); - - if (m) { - markers.push(m); - } - } else if (marker) { - markers.push( - typeof marker === "object" - ? new maplibregl.Marker(marker) - : createMarker().setLngLat(picked.center).addTo(map), - ); - } - } - - if (showResultMarkers) { - for (const feature of markedFeatures ?? []) { - if (feature === picked) { - continue; - } - - let marker; - - if (showResultMarkers instanceof Function) { - marker = showResultMarkers(map, feature); - - if (!marker) { - continue; - } - } else { - marker = ( - typeof showResultMarkers === "object" - ? new maplibregl.Marker(showResultMarkers) - : createMarker(true) - ) - .setLngLat(feature.center) - .setPopup( - new maplibregl.Popup({ - offset: [1, -27], - closeButton: false, - closeOnMove: true, - className: "maptiler-gc-popup", - }).setText( - feature.place_type[0] === "reverse" - ? feature.place_name - : feature.place_name.replace(/,.*/, ""), - ), - ) - .addTo(map); - } - - const element = marker.getElement(); - - element.addEventListener("click", (e) => { - e.stopPropagation(); - - eventHandler?.({ type: "markerClick", id: feature.id }); - }); - - element.addEventListener("mouseenter", () => { - eventHandler?.({ type: "markerMouseEnter", id: feature.id }); - - marker.togglePopup(); - }); - - element.addEventListener("mouseleave", () => { - eventHandler?.({ type: "markerMouseLeave", id: feature.id }); - - marker.togglePopup(); - }); - - // element.classList.toggle("marker-fuzzy", !!feature.matching_text); - - markers.push(marker); - } - } - }, - - setSelectedMarker(index: number): void { - if (selectedMarker) { - selectedMarker.getElement().classList.toggle("marker-selected", false); - } - - selectedMarker = index > -1 ? markers[index] : undefined; - - selectedMarker?.getElement().classList.toggle("marker-selected", true); - }, - - getCenterAndZoom() { - const c = map.getCenter(); - - return [map.getZoom(), c.lng, c.lat]; - }, - } satisfies MapController; -} diff --git a/src/maplibregl.ts b/src/maplibregl.ts index 72a05c5..7a25f40 100644 --- a/src/maplibregl.ts +++ b/src/maplibregl.ts @@ -1,44 +1,7 @@ -import type { Map } from "maplibre-gl"; -import * as maplibregl from "maplibre-gl"; -import { - crateClasses, - type MapLibreBaseControlOptions, -} from "./MapLibreBasedGeocodingControl"; -export { createMapLibreGlMapController } from "./maplibregl-controller"; - -type Options = MapLibreBaseControlOptions & { - /** - * Maptiler API key. Optional if used with MapTiler SDK. - */ - apiKey?: string; -}; - -const { MapLibreBasedGeocodingControl, events } = crateClasses( - maplibregl.Evented, - maplibregl, -); - -export class GeocodingControl - extends MapLibreBasedGeocodingControl - implements maplibregl.IControl -{ - onAdd(map: Map): HTMLElement { - return super.onAddInt(map); - } -} - -export const SelectEvent = events.SelectEvent; - -export const FeaturesListedEvent = events.FeaturesListedEvent; - -export const FeaturesMarkedEvent = events.FeaturesMarkedEvent; - -export const OptionsVisibilityChangeEvent = events.OptionsVisibilityChangeEvent; - -export const PickEvent = events.PickEvent; - -export const QueryChangeEvent = events.QueryChangeEvent; - -export const ResponseEvent = events.ResponseEvent; - -export const ReverseToggleEvent = events.ReverseToggleEvent; +export * from "."; +export * from "./components/marker"; +export * from "./controls/maplibregl-control"; +export { MaplibreglGeocodingControl as GeocodingControl } from "./controls/maplibregl-control"; +export type * as GeocodingControlEvent from "./controls/maplibregl-events"; +export * from "./controls/maplibregl-options"; +export type { MaplibreglGeocodingControlOptions as GeocodingControlOptions } from "./controls/maplibregl-options"; diff --git a/src/maptilersdk.ts b/src/maptilersdk.ts index 0f7eded..c4eb861 100644 --- a/src/maptilersdk.ts +++ b/src/maptilersdk.ts @@ -1,63 +1,7 @@ -import * as maptilersdk from "@maptiler/sdk"; -import type * as maplibregl from "maplibre-gl"; -import type { Map } from "maplibre-gl"; -import { - crateClasses, - type MapLibreBaseControlOptions, -} from "./MapLibreBasedGeocodingControl"; -import { name, version } from "./info.json"; - -export { createMapLibreGlMapController } from "./maplibregl-controller"; - -const { MapLibreBasedGeocodingControl, events } = - crateClasses( - maptilersdk.Evented, - maptilersdk, - (map: Map, div: HTMLElement) => { - const sdkConfig: { apiKey?: string; language?: string } = {}; - - if (!("getSdkConfig" in map && typeof map.getSdkConfig === "function")) { - throw new Error("MapTiler SDK not detected"); - } - - const { primaryLanguage, apiKey } = map.getSdkConfig(); - - sdkConfig.apiKey = apiKey; - - const match = /^([a-z]{2})($|_|-)/.exec(primaryLanguage); - - if (match) { - sdkConfig.language = match[1]; - } - - div.className += " maptiler-ctrl"; - - return sdkConfig; - }, - ); - -export class GeocodingControl - extends MapLibreBasedGeocodingControl - implements maptilersdk.IControl -{ - onAdd(map: maptilersdk.Map): HTMLElement { - map.telemetry?.registerModule(name, version); - return super.onAddInt(map as unknown as maplibregl.Map); - } -} - -export const SelectEvent = events.SelectEvent; - -export const FeaturesListedEvent = events.FeaturesListedEvent; - -export const FeaturesMarkedEvent = events.FeaturesMarkedEvent; - -export const OptionsVisibilityChangeEvent = events.OptionsVisibilityChangeEvent; - -export const PickEvent = events.PickEvent; - -export const QueryChangeEvent = events.QueryChangeEvent; - -export const ResponseEvent = events.ResponseEvent; - -export const ReverseToggleEvent = events.ReverseToggleEvent; +export * from "."; +export * from "./components/marker"; +export * from "./controls/maptilersdk-control"; +export { MaptilerGeocodingControl as GeocodingControl } from "./controls/maptilersdk-control"; +export type * as GeocodingControlEvent from "./controls/maptilersdk-events"; +export * from "./controls/maptilersdk-options"; +export type { MaptilerGeocodingControlOptions as GeocodingControlOptions } from "./controls/maptilersdk-options"; diff --git a/src/openlayers-controller.ts b/src/openlayers-controller.ts deleted file mode 100644 index 4d8ee07..0000000 --- a/src/openlayers-controller.ts +++ /dev/null @@ -1,413 +0,0 @@ -import type { FeatureCollection, MultiPolygon, Polygon } from "geojson"; -import { Feature as OlFeature, type MapBrowserEvent } from "ol"; -import type { FeatureLike } from "ol/Feature"; -import type Map from "ol/Map"; -import type { AnimationOptions, FitOptions } from "ol/View"; -import { - GeometryCollection as OlGeometryCollection, - LineString as OlLineString, - MultiLineString as OlMultiLineString, - MultiPolygon as OlMultiPolygon, - Point as OlPoint, - Polygon as OlPolygon, - type Geometry as OlGeometry, -} from "ol/geom"; -import VectorLayer from "ol/layer/Vector"; -import { - fromLonLat, - getUserProjection, - toLonLat, - transformExtent, -} from "ol/proj"; -import VectorSource from "ol/source/Vector"; -import Fill from "ol/style/Fill"; -import Icon from "ol/style/Icon"; -import Stroke from "ol/style/Stroke"; -import Style, { type StyleLike } from "ol/style/Style"; -import Text from "ol/style/Text"; -import type { FlatStyleLike } from "ol/style/flat"; -import { setMask } from "./mask"; -import type { - BBox, - Feature as FeatureType, - MapController, - MapEvent, - Position, -} from "./types"; - -const EPSG_4326 = "EPSG:4326"; - -function defaultStyle(feature: FeatureLike) { - const properties = feature.getProperties(); - - const { isMask } = properties; - - const type = feature.getGeometry()?.getType(); - - const weight = isMask - ? 0 - : type === "LineString" || type === "MultiLineString" - ? 3 - : 2; - - return new Style({ - stroke: isMask - ? undefined - : new Stroke({ - color: "#3170fe", - lineDash: [weight, weight], - width: weight, - lineCap: "butt", - }), - fill: isMask - ? new Fill({ - color: "#00000020", - }) - : undefined, - image: new Icon({ - src: `/icons/marker_${ - properties.isReverse - ? "reverse" - : properties.isSelected - ? "selected" - : "unselected" - }.svg`, - anchor: [0.5, 1], - }), - zIndex: properties.isSelected ? 2 : properties.isReverse ? 0 : 1, - text: - properties.isSelected && properties.tooltip - ? new Text({ - backgroundFill: new Fill({ color: "white" }), - text: properties.tooltip, - offsetY: -40, - backgroundStroke: new Stroke({ - color: "white", - lineJoin: "round", - width: 3, - }), - padding: [2, 0, 0, 2], - }) - : undefined, - }); -} - -export function createOpenLayersMapController( - map: Map, - flyToOptions: AnimationOptions = {}, - flyToBounds: FitOptions = {}, - fullGeometryStyle: StyleLike | FlatStyleLike = defaultStyle, -) { - let prevSelected = -1; - - let prevHovered: string | undefined; - - let eventHandler: ((e: MapEvent) => void) | undefined; - - let reverseMarker: OlFeature | undefined; - - let indicatingReverse = false; - - const vectorLayer = new VectorLayer({ - updateWhileAnimating: true, - }); - - map.addLayer(vectorLayer); - - const source = new VectorSource({}); - - vectorLayer.setSource(source); - - vectorLayer.setStyle(fullGeometryStyle); - - map.on("click", (e) => { - map.forEachFeatureAtPixel(e.pixel, (feature) => { - const id = feature.getId() as string; - - if (!id) { - return; - } - - e.stopPropagation(); - - eventHandler?.({ type: "markerClick", id }); - - return feature; - }); - }); - - map.on("pointermove", (e) => { - const featureId = map.forEachFeatureAtPixel(e.pixel, (feature) => { - return feature.getId() as string | undefined; - }); - - if (prevHovered === featureId) { - return; - } - - if (prevHovered) { - eventHandler?.({ - type: "markerMouseLeave", - id: prevHovered, - }); - } - - if (featureId) { - eventHandler?.({ - type: "markerMouseEnter", - id: featureId, - }); - } - - map.getTargetElement().style.cursor = featureId - ? "pointer" - : indicatingReverse - ? "crosshair" - : ""; - - prevHovered = featureId; - }); - - function getProjection() { - return getUserProjection() ?? map.getView().getProjection(); - } - - function fromWgs84(geometry: OlGeometry) { - return geometry.transform(EPSG_4326, getProjection()); - } - - const handleMapClick = (e: MapBrowserEvent) => { - eventHandler?.({ - type: "mapClick", - coordinates: toLonLat(e.coordinate, getProjection()) as [number, number], - }); - }; - - return { - setEventHandler(handler: undefined | ((e: MapEvent) => void)): void { - if (handler) { - eventHandler = handler; - map.on("click", handleMapClick); - } else { - eventHandler = undefined; - map.un("click", handleMapClick); - } - }, - - flyTo(center: Position, zoom: number) { - map.getView().animate({ - center: fromLonLat(center, getProjection()), - ...(zoom ? { zoom } : {}), - duration: 2000, - ...flyToOptions, - }); - }, - - fitBounds(bbox: BBox, padding: number, maxZoom: number): void { - map.getView().fit(transformExtent(bbox, EPSG_4326, getProjection()), { - padding: [padding, padding, padding, padding], - ...(maxZoom ? { maxZoom } : {}), - duration: 2000, - ...flyToBounds, - }); - }, - - indicateReverse(reverse: boolean): void { - indicatingReverse = reverse; - - map.getTargetElement().style.cursor = reverse ? "crosshair" : ""; - }, - - setReverseMarker(coordinates?: Position) { - if (reverseMarker) { - if (!coordinates) { - source.removeFeature(reverseMarker); - - reverseMarker.dispose(); - - reverseMarker = undefined; - } else { - (reverseMarker.getGeometry() as OlPoint).setCoordinates( - fromLonLat(coordinates, getProjection()), - ); - } - } else if (coordinates) { - reverseMarker = new OlFeature( - new OlPoint(fromLonLat(coordinates, getProjection())), - ); - - reverseMarker.setProperties({ isReverse: true }); - - source.addFeature(reverseMarker); - } - }, - - setFeatures( - markedFeatures: FeatureType[] | undefined, - picked: FeatureType | undefined, - showPolygonMarker: boolean, - ): void { - function setData(data?: FeatureCollection) { - if (!data) { - return; - } - - for (const f of data.features) { - const geom = - f.geometry.type === "Polygon" - ? new OlPolygon(f.geometry.coordinates) - : f.geometry.type === "MultiPolygon" - ? new OlMultiPolygon(f.geometry.coordinates) - : null; - - if (!geom) { - continue; - } - - source.addFeature( - new OlFeature({ - isMask: !!f.properties?.isMask, - geometry: fromWgs84(geom), - }), - ); - } - } - - source.clear(); - - if (reverseMarker) { - source.addFeature(reverseMarker); - } - - block: if (picked) { - let handled = false; - - if (picked.geometry.type === "GeometryCollection") { - const geoms = picked.geometry.geometries - .map((geometry) => - geometry.type === "Polygon" - ? new OlPolygon(geometry.coordinates) - : geometry.type === "MultiPolygon" - ? new OlMultiPolygon(geometry.coordinates) - : null, - ) - .filter((a: T | null): a is T => !!a); - - if (geoms.length > 0) { - source.addFeature( - new OlFeature(fromWgs84(new OlGeometryCollection(geoms))), - ); - - handled = true; - } else { - for (const geometry of picked.geometry.geometries) { - if (geometry.type === "LineString") { - source.addFeature( - new OlFeature( - fromWgs84(new OlLineString(geometry.coordinates)), - ), - ); - - handled = true; - } else if (geometry.type === "MultiLineString") { - source.addFeature( - new OlFeature( - fromWgs84(new OlMultiLineString(geometry.coordinates)), - ), - ); - } - - handled = true; - } - } - } - - if (handled) { - // nothing - } else if (picked.geometry.type === "Polygon") { - setMask(picked as FeatureType, setData); - } else if (picked.geometry.type === "MultiPolygon") { - setMask(picked as FeatureType, setData); - } else if (picked.geometry.type === "LineString") { - source.addFeature( - new OlFeature( - fromWgs84(new OlLineString(picked.geometry.coordinates)), - ), - ); - - break block; // no pin for (multi)linestrings - } else if (picked.geometry.type === "MultiLineString") { - source.addFeature( - new OlFeature( - fromWgs84(new OlMultiLineString(picked.geometry.coordinates)), - ), - ); - - break block; // no pin for (multi)linestrings - } - - if (!showPolygonMarker && !picked.geometry.type.endsWith("Point")) { - break block; - } - - source.addFeature(new OlFeature(fromWgs84(new OlPoint(picked.center)))); - } - - for (const feature of markedFeatures ?? []) { - if (feature === picked) { - continue; - } - - const marker = new OlFeature( - new OlPoint(fromLonLat(feature.center, getProjection())), - ); - - marker.setId(feature.id); - - marker.setProperties({ - fuzzy: !!feature.matching_text, - tooltip: - feature.place_type[0] === "reverse" - ? feature.place_name - : feature.place_name.replace(/,.*/, ""), - }); - - source.addFeature(marker); - } - }, - - setSelectedMarker(index: number): void { - const features = source.getFeatures(); - - const offset = features[0]?.getProperties().isReverse ? 1 : 0; - - if (prevSelected > -1) { - features[prevSelected + offset]?.setProperties({ - isSelected: false, - }); - } - - if (index > -1) { - features[index + offset]?.setProperties({ - isSelected: true, - }); - } - - prevSelected = index; - }, - - getCenterAndZoom() { - const view = map.getView(); - - const center = view.getCenter(); - - const zoom = view.getZoom(); - - if (!center || zoom === undefined) { - return undefined; - } - - return [zoom, ...(toLonLat(center, getProjection()) as Position)]; - }, - } satisfies MapController; -} diff --git a/src/openlayers.ts b/src/openlayers.ts deleted file mode 100644 index 856d600..0000000 --- a/src/openlayers.ts +++ /dev/null @@ -1,289 +0,0 @@ -import type { Map } from "ol"; -import type { ObjectEvent } from "ol/Object"; -import type { CombinedOnSignature, EventTypes } from "ol/Observable"; -import type { AnimationOptions, FitOptions } from "ol/View"; -import { Control } from "ol/control"; -import type { Options } from "ol/control/Control"; -import type { EventsKey } from "ol/events"; -import BaseEvent from "ol/events/Event"; -import type { StyleLike } from "ol/style/Style"; -import type { FlatStyleLike } from "ol/style/flat"; -import GeocodingControlComponent from "./GeocodingControl.svelte"; -import { createOpenLayersMapController } from "./openlayers-controller"; -import type { ControlOptions, Feature, FeatureCollection } from "./types"; -export { createOpenLayersMapController } from "./openlayers-controller"; - -type OpenLayersControlOptions = ControlOptions & - Options & { - flyTo?: boolean | (AnimationOptions & FitOptions); - fullGeometryStyle?: StyleLike | FlatStyleLike; - }; - -type CustomEventMap = { - select: SelectEvent; - featureslisted: FeaturesListedEvent; - featuresmarked: FeaturesMarkedEvent; - optionsvisibilitychange: OptionsVisibilityChangeEvent; - pick: PickEvent; - querychange: QueryChangeEvent; - response: ResponseEvent; - reversetoggle: ReverseToggleEvent; -}; - -type CustomObjectOnSignature = { - ( - type: K, - listener: (evt: CustomEventMap[K]) => void, - ): ReturnType; -} & { - (type: "propertychange", listener: (evt: ObjectEvent) => void): ReturnType; -} & CombinedOnSignature< - EventTypes | "propertychange" | keyof CustomEventMap, - ReturnType - >; - -export class GeocodingControl extends Control { - #gc?: GeocodingControlComponent; - - #options: OpenLayersControlOptions; - - declare on: CustomObjectOnSignature; - declare once: CustomObjectOnSignature; - declare un: CustomObjectOnSignature; - - constructor(options: OpenLayersControlOptions) { - const div = document.createElement("div"); - - div.className = "ol-search"; - - super({ - element: div, - target: options.target, - }); - - const { flyTo, fullGeometryStyle, ...restOptions } = options; - - this.#gc = new GeocodingControlComponent({ - target: div, - props: { - flyTo: flyTo === undefined ? true : !!flyTo, - ...restOptions, - }, - }); - - this.#gc.$on("select", (event) => { - this.dispatchEvent(new SelectEvent(event.detail.feature)); - }); - - this.#gc.$on("pick", (event) => { - this.dispatchEvent(new PickEvent(event.detail.feature)); - }); - - this.#gc.$on("featureslisted", (event) => { - this.dispatchEvent(new FeaturesListedEvent(event.detail.features)); - }); - - this.#gc.$on("featuresmarked", (event) => { - this.dispatchEvent(new FeaturesMarkedEvent(event.detail.features)); - }); - - this.#gc.$on("response", (event) => { - this.dispatchEvent( - new ResponseEvent(event.detail.url, event.detail.featureCollection), - ); - }); - - this.#gc.$on("optionsvisibilitychange", (event) => { - this.dispatchEvent( - new OptionsVisibilityChangeEvent(event.detail.optionsVisible), - ); - }); - - this.#gc.$on("reversetoggle", (event) => { - this.dispatchEvent(new ReverseToggleEvent(event.detail.reverse)); - }); - - this.#gc.$on("querychange", (event) => { - this.dispatchEvent(new QueryChangeEvent(event.detail.query)); - }); - - this.#options = options; - } - - setMap(map: Map | null): void { - super.setMap(map); - - if (map) { - const { - // marker, - // showResultMarkers, - flyTo, - fullGeometryStyle, - } = this.#options; - - const mapController = createOpenLayersMapController( - map, - typeof flyTo === "boolean" ? undefined : flyTo, - typeof flyTo === "boolean" ? undefined : flyTo, - // marker, - // showResultMarkers, - fullGeometryStyle, - ); - - this.#gc?.$set({ mapController }); - } - } - - /** - * Update the control options. - * - * @param options options to update - */ - setOptions(options: OpenLayersControlOptions) { - Object.assign(this.#options, options); - - const { flyTo, fullGeometryStyle, ...restOptions } = this.#options; - - this.#gc?.$set({ - ...restOptions, - flyTo: flyTo === undefined ? true : !!flyTo, - }); - } - - /** - * Set the content of search input box. - * - * @param value text to set - * @param submit perform the search - */ - setQuery(value: string, submit = true) { - this.#gc?.setQuery(value, submit); - } - - /** - * Clear geocoding search results from the map. - */ - clearMap() { - this.#gc?.clearMap(); - } - - /** - * Clear search result list. - */ - clearList() { - this.#gc?.clearList(); - } - - /** - * Set reverse geocoding mode. - * - * @param reverseActive reverse geocoding active - */ - setReverseMode(reverseActive: boolean) { - this.#gc?.$set({ reverseActive }); - } - - /** - * Focus the search input box. - * - * @param options [FocusOptions](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus#options) - */ - focus(options?: FocusOptions) { - this.#gc?.focus(options); - } - - /** - * Blur the search input box. - */ - blur() { - this.#gc?.blur(); - } - - // onRemove() { - // this.#gc?.$destroy(); - // } -} - -export class SelectEvent extends BaseEvent { - feature: Feature | undefined; - - constructor(feature: Feature | undefined) { - super("select"); - - this.feature = feature; - } -} - -export class FeaturesListedEvent extends BaseEvent { - features: Feature[] | undefined; - - constructor(features: Feature[] | undefined) { - super("featureslisted"); - - this.features = features; - } -} - -export class FeaturesMarkedEvent extends BaseEvent { - features: Feature[] | undefined; - - constructor(features: Feature[] | undefined) { - super("featuresmarked"); - - this.features = features; - } -} - -export class OptionsVisibilityChangeEvent extends BaseEvent { - optionsVisible: boolean; - - constructor(optionsVisible: boolean) { - super("optionsvisibilitychange"); - - this.optionsVisible = optionsVisible; - } -} - -export class PickEvent extends BaseEvent { - feature: Feature | undefined; - - constructor(feature: Feature | undefined) { - super("pick"); - - this.feature = feature; - } -} - -export class QueryChangeEvent extends BaseEvent { - query: string; - - constructor(query: string) { - super("querychange"); - - this.query = query; - } -} - -export class ResponseEvent extends BaseEvent { - url: string; - - featureCollection: FeatureCollection; - - constructor(url: string, featureCollection: FeatureCollection) { - super("response"); - - this.url = url; - - this.featureCollection = featureCollection; - } -} - -export class ReverseToggleEvent extends BaseEvent { - reverse: boolean; - - constructor(reverse: boolean) { - super("reversetoggle"); - - this.reverse = reverse; - } -} diff --git a/src/react.ts b/src/react.ts deleted file mode 100644 index bbf4ce6..0000000 --- a/src/react.ts +++ /dev/null @@ -1,201 +0,0 @@ -import { - createElement, - forwardRef, - useEffect, - useImperativeHandle, - useRef, - type Ref, -} from "react"; -import GeocodingControl from "./GeocodingControl.svelte"; -import type { ControlOptions, DispatcherTypeCC, MapController } from "./types"; - -type EventNames = keyof DispatcherTypeCC; - -type EventHandlerFnName = `on${Capitalize}`; - -type CallbackProperties = { - [K in keyof T as EventHandlerFnName>]?: ( - event: T[K], - ) => void; -}; - -const eventNames = [ - "featuresListed", - "featuresMarked", - "optionsVisibilityChange", - "pick", - "queryChange", - "response", - "reverseToggle", - "select", -] as const satisfies readonly EventNames[]; - -type MapControllerProp = { - mapController?: MapController; -}; - -const propertyNames = [ - "adjustUrlQuery", - "adjustUrl", - "apiKey", - "apiUrl", - "bbox", - "class", - "clearButtonTitle", - "clearListOnPick", - "clearOnBlur", - "collapsed", - "country", - "debounceSearch", - "enableReverse", - "errorMessage", - "excludeTypes", - "reverseGeocodingExcludeTypes", - "exhaustiveReverseGeocoding", - "fetchParameters", - "filter", - "flyToSelected", - "fuzzyMatch", - "iconsBaseUrl", - "keepListOpen", - "language", - "limit", - "reverseGeocodingLimit", - "mapController", - "markerOnSelected", - "minLength", - "noResultsMessage", - "pickedResultStyle", - "placeholder", - "proximity", - "reverseActive", - "reverseButtonTitle", - "selectFirst", - "showPlaceType", - "showResultsWhileTyping", - "types", - "reverseGeocodingTypes", - "zoom", -] as const satisfies readonly (keyof (ControlOptions & MapControllerProp))[]; - -function getEventFnName(name: T): EventHandlerFnName { - return ("on" + - name[0].toUpperCase() + - name.slice(1)) as EventHandlerFnName; -} - -export type Props = ControlOptions & - CallbackProperties & - MapControllerProp; - -// defining the type explicitly otherwise compiled .d.ts refers to .svelte which is not good -// type MethodNames = "blur" | "focus" | "setQuery"; -// export type Methods = { [T in MethodNames]: GeocodingControl[T] }; -export type Methods = { - /** - * Blur the search input box. - */ - blur(): void; - - /** - * Focus the search input box. - * - * @param options [FocusOptions](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus#options) - */ - focus(options?: FocusOptions): void; - - /** - * Set the content of search input box. - * - * @param value text to set - * @param submit perform the search - */ - setQuery(value: string, submit?: boolean): void; - - /** - * Clear geocoding search results from the map. - */ - clearMap(): void; - - /** - * Clear search result list. - */ - clearList(): void; - - /** - * Set reverse geocoding mode. - * - * @param reverseActive reverse geocoding active - */ - setReverseMode(reverseActive: boolean): void; -}; - -const ReactGeocodingControl = forwardRef(function ReactGeocodingControl( - props: Props, - ref: Ref, -) { - const divRef = useRef(undefined); - - const controlRef = useRef(undefined); - - const options = { ...props }; - - for (const eventName of eventNames) { - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete - delete options[getEventFnName(eventName)]; - } - - useEffect(() => { - if (!divRef.current) { - throw new Error(); - } - - const control = new GeocodingControl({ - target: divRef.current, - props: options, - }); - - controlRef.current = control; - - return () => control.$destroy(); - }, []); - - // watch change on every option - for (const propName of propertyNames) { - useEffect(() => { - if (controlRef.current && props[propName] !== undefined) { - controlRef.current.$set({ [propName]: props[propName] }); - } - }, [props[propName]]); - } - - // attach event handlers - for (const eventName of eventNames) { - const eventHandlerFn = props[getEventFnName(eventName)]; - - useEffect( - () => - eventHandlerFn && - controlRef.current?.$on(eventName.toLowerCase(), (e) => { - eventHandlerFn(e.detail as never); - }), - - [eventHandlerFn], - ); - } - - useImperativeHandle(ref, () => ({ - setQuery: (value: string, submit = true) => - controlRef.current?.setQuery(value, submit), - clearMap: () => controlRef.current?.clearMap(), - clearList: () => controlRef.current?.clearList(), - focus: (options?: FocusOptions) => controlRef.current?.focus(options), - blur: () => controlRef.current?.blur(), - setReverseMode: (reverseActive: boolean) => - controlRef.current?.$set({ reverseActive }), - })); - - return createElement("div", { ref: divRef }); -}); - -export { ReactGeocodingControl as GeocodingControl }; diff --git a/src/types.ts b/src/types.ts index 005db6a..78dbaee 100644 --- a/src/types.ts +++ b/src/types.ts @@ -21,34 +21,6 @@ export type FeatureCollection = { features: Feature[]; }; -export type MapEvent = - | { type: "mapClick"; coordinates: Position } - | { type: "markerClick"; id: string } - | { type: "markerMouseEnter"; id: string } - | { type: "markerMouseLeave"; id: string }; - -export type MapController = { - setEventHandler(handler: undefined | ((e: MapEvent) => void)): void; - - flyTo(center: Position, zoom?: number): void; - - fitBounds(bbox: BBox, padding: number, maxZoom?: number): void; - - indicateReverse(reverse: boolean): void; - - setFeatures( - features: Feature[] | undefined, - picked: Feature | undefined, - showPolygonMarker: boolean, - ): void; - - setReverseMarker(coordinates?: Position): void; - - setSelectedMarker(index: number): void; - - getCenterAndZoom(): [zoom: number, lon: number, lat: number] | undefined; -}; - export type ProximityRule = { /** minimal map zoom for the rule to be used */ minZoom?: number; @@ -80,367 +52,10 @@ export type ProximityRule = { } & PositionOptions) ); -export type ControlOptions = { - /** - * Callback function to adjust URL search parameters. - * - * Default: Empty function. - * - * @deprecated Use `adjustUrl` instead. - */ - adjustUrlQuery?: (sp: URLSearchParams) => void; - - /** - * Callback function to adjust the geocoding URL before fetching. - * - * @param url [URL](https://developer.mozilla.org/en-US/docs/Web/API/URL) parameter that can be modified. - * - * Default: Empty function. - */ - adjustUrl?: (url: URL) => void; - - /** - * MapTiler API key. - */ - apiKey?: string; - - /** - * Geocoding API URL. - * - * Default: MapTiler Geocoding API URL. - */ - apiUrl?: string; - - /** - * Bounding box in the format `[minX, minY, maxX, maxY]` to limit search results. - * - * Default: `undefined`. - */ - bbox?: BBox; - - /** - * CSS class for the root element. - * - * Default: `undefined`. - */ - class?: string; - - /** - * Title of the clear button. - * - * Default: `"clear"`. - */ - clearButtonTitle?: string; - - /** - * Clears the result list after picking an item. - * Prevents redisplaying the list when the input box is focused. - * - * Default: `false`. - */ - clearListOnPick?: boolean; - - /** - * Clears the input value when it loses focus. - * - * Default: `false`. - */ - clearOnBlur?: boolean; - - /** - * Collapses the geocoder control until hovered or focused. - * - * Default: `false`. - */ - collapsed?: boolean; - - /** - * Limits search to the specified country or countries. - * - * Default: `undefined` (all countries). - */ - country?: string | string[]; - - /** - * Time delay (in milliseconds) before querying the server after typing in the input box. - * Useful for reducing the number of API calls. - * - * Default: `200`. - */ - debounceSearch?: number; - - /** - * Enables reverse geocoding: - * - `"button"`: Enables reverse geocoding button. - * - `"always"`: Reverse geocoding is always active. - * - * Default: `"never"`. - */ - enableReverse?: EnableReverse; - - /** - * Custom error message. - * - * Default: `"Something went wrong…"`. - */ - errorMessage?: string; - - /** - * Includes all available types except those listed in the `types` option. - * - * See `reverseGeocodingExcludeTypes` for reverse geocoding exclusion. - * - * Default: `false`. - */ - excludeTypes?: boolean; - - /** - * Uses the `limit` option value for reverse geocoding even if the `types` option has multiple elements. - * Works only if enabled on the server. - * - * Default: `false`. - */ - exhaustiveReverseGeocoding?: boolean; - - /** - * Additional parameters for fetch requests. - * - * Default: `undefined`. - */ - fetchParameters?: RequestInit; - - /** - * Callback function to filter results from the Geocoding API response. - * The function should return `true` to keep an item, or `false` to exclude it. - * - * Default: A function that always returns `true`. - */ - filter?: (feature: Feature) => boolean; - - /** - * Animates the map to the selected feature from the result list. - * - * Default: `false`. - */ - flyToSelected?: boolean; - - /** - * Enables fuzzy search. - * - * Default: `true`. - */ - fuzzyMatch?: boolean; - - /** - * Base URL for POI icons. - * - * Default: - * - `"icons/"` for Svelte apps. - * - `"https://cdn.maptiler.com/maptiler-geocoding-control/v${version}/icons/"` for others. - */ - iconsBaseUrl?: string; - - /** - * Keeps the result list open even if the control is unfocused. - * - * Default: `false`. - */ - keepListOpen?: boolean; - - /** - * Language for response text and query weighting. - * Accepts IETF language tags. - * Set to `null` or an empty string to disable language-specific searching. - * - * Default: `undefined` (uses the browser's language settings). - */ - language?: string | string[] | null; - - /** - * Maximum number of results to display. - * - * See `reverseGeocodingLimit` for reverse geocoding limits. - * - * Default: `5`. - */ - limit?: number; - - /** - * Displays a marker on the selected feature from the result list. - * - * Default: `true`. - */ - markerOnSelected?: boolean; - - /** - * Minimum number of characters required to start a search. - * - * Default: `2`. - */ - minLength?: number; - - /** - * Custom message for when no results are found. - * - * Default: - * ``` - * "Oops! Looks like you're trying to predict something that's not quite right. - * We can't seem to find what you're looking for. Maybe try double-checking your spelling or try a different search term. - * Keep on typing - we'll do our best to get you where you need to go!" - * ``` - */ - noResultsMessage?: string; - - /** - * Style of the picked result on the map: - * - `"marker-only"`: Show only a marker at the center of the feature. - * - `"full-geometry"`: Display the full feature geometry. - * - `"full-geometry-including-polygon-center-marker"`: Display full geometry with a marker at the polygon center. - * - * Default: `"full-geometry"`. - */ - pickedResultStyle?: PickedResultStyle; - - /** - * Custom placeholder for the input box. - * - * Default: `"Search"`. - */ - placeholder?: string; - - /** - * Prioritizes search results closer to a proximity point. - * The first matching rule in the array is used. - * Set to `null` to disable proximity. - * - * Default: `[ { type: "server-geolocation" } ]`. - */ - proximity?: ProximityRule[] | null; - - /** - * Activates reverse geocoding. - * - * Default: `false`. - */ - reverseActive?: boolean; - - /** - * Title of the reverse geocoding toggle button. - * - * Default: `"toggle reverse geocoding"`. - */ - reverseButtonTitle?: string; - - /** - * Excludes types for reverse geocoding. - * - * Default: Same as `excludeTypes`. - */ - reverseGeocodingExcludeTypes?: boolean; - - /** - * Limits results for reverse geocoding. - * Applied only if value is 1 or effective types contain a single value. - * - * See also `reverseGeocodingTypes` option. - * - * Default: The value of the `limit` option if set. If effective types contain a single value, the default is `1`. In all other cases, this option is not used. - */ - reverseGeocodingLimit?: number; - - /** - * Specifies types for reverse geocoding. - * - * If effective types are multiple values, the `limit`/`reverseGeocodingLimit` option is ignored. - * - * See also `reverseGeocodingLimit` option. - * - * Default: Same as `types`. - */ - reverseGeocodingTypes?: TypeRule[]; - - /** - * Automatically selects the first feature in the result list. - * - * Default: `true`. - */ - selectFirst?: boolean; - - /** - * Indicates when to show place/POI types in the dropdown: - * - `"never"`: Hide the type. - * - `"always"`: Always show the type. - * - `"if-needed"`: Show the type only if it cannot be determined from the icon. - * - * Default: `"if-needed"`. - */ - showPlaceType?: ShowPlaceType; - - /** - * Displays results while typing: - * - `false`: Search occurs only on pressing the Enter key. - * - `true`: Search begins when the input meets the `minLength` requirement. - * - * Default: `true`. - */ - showResultsWhileTyping?: boolean; - - /** - * Types to query, either as an array or `[minZoom, maxZoom, type]` format. - * `minZoom` is inclusive, `maxZoom` is exclusive, and either can be `null` or `undefined` for unbounded values. - * - * See `reverseGeocodingTypes` option for reverse geocoding types. - * - * Default: `undefined` (uses server default feature types). - */ - types?: TypeRule[]; - - /** - * Specifies the zoom level to animate the map to for a geocoded result when no bounding box is present or when the result is a point. - * If a bounding box is present and not a point, the map will fit to the bounding box. - * - * Values are key-value pairs where the key is a `` or `.` and the value is the zoom level. - * - * Default: `GeocodingControl.ZOOM_DEFAULTS`. - */ - zoom?: Record; -}; - -export type PickedResultStyle = - | "marker-only" - | "full-geometry" - | "full-geometry-including-polygon-center-marker"; +export type PickedResultStyle = "marker-only" | "full-geometry" | "full-geometry-including-polygon-center-marker"; export type EnableReverse = "never" | "always" | "button"; export type ShowPlaceType = "never" | "always" | "if-needed"; -export type DispatcherTypeCC = { - featuresListed: { features: Feature[] | undefined }; - featuresMarked: { features: Feature[] | undefined }; - optionsVisibilityChange: { optionsVisible: boolean }; - pick: { feature: Feature | undefined }; - queryChange: { query: string }; - response: { url: string; featureCollection: FeatureCollection }; - reverseToggle: { reverse: boolean }; - select: { feature: Feature | undefined }; -}; - -export type DispatcherType = { - [T in keyof DispatcherTypeCC as Lowercase]: DispatcherTypeCC[T]; -}; - -export type RedefineType< - OriginalType, - UpdatedType extends { [K in keyof OriginalType]: OriginalType[K] } & { - [K in Exclude]: never; - }, -> = UpdatedType; - -export type TypeRule = - | string - | [ - minZoom: number | null | undefined, - maxZoom: number | null | undefined, - type: string, - ]; +export type TypeRule = string | [minZoom: number | null | undefined, maxZoom: number | null | undefined, type: string]; diff --git a/src/geoUtils.ts b/src/utils/geo-utils.ts similarity index 60% rename from src/geoUtils.ts rename to src/utils/geo-utils.ts index a787474..57bb076 100644 --- a/src/geoUtils.ts +++ b/src/utils/geo-utils.ts @@ -1,11 +1,7 @@ -import type { BBox } from "./types"; +import type { BBox } from "../types"; // taken from Leaflet -export function wrapNum( - x: number, - range: [number, number], - includeMax: boolean, -) { +export function wrapNum(x: number, range: [number, number], includeMax: boolean) { const max = range[1], min = range[0], d = max - min; @@ -17,10 +13,7 @@ export function unwrapBbox(bbox0: BBox): BBox { const bbox = [...bbox0] satisfies BBox; if (bbox[2] < bbox[0]) { - if ( - Math.abs((bbox[0] + bbox[2] + 360) / 2) > - Math.abs((bbox[0] - 360 + bbox[2]) / 2) - ) { + if (Math.abs((bbox[0] + bbox[2] + 360) / 2) > Math.abs((bbox[0] - 360 + bbox[2]) / 2)) { bbox[0] -= 360; } else { bbox[2] += 360; diff --git a/src/mask.ts b/src/utils/mask.ts similarity index 77% rename from src/mask.ts rename to src/utils/mask.ts index 8015656..3628b54 100644 --- a/src/mask.ts +++ b/src/utils/mask.ts @@ -3,19 +3,11 @@ import difference from "@turf/difference"; import flatten from "@turf/flatten"; import { featureCollection, polygon } from "@turf/helpers"; import union from "@turf/union"; -import type { - Feature, - FeatureCollection, - MultiPolygon, - Polygon, -} from "geojson"; -import { unwrapBbox } from "./geoUtils"; -import type { BBox } from "./types"; +import type { Feature, FeatureCollection, MultiPolygon, Polygon } from "geojson"; +import type { BBox } from "../types"; +import { unwrapBbox } from "./geo-utils"; -export function setMask( - picked: Feature, - setData: (data?: FeatureCollection) => void, -): void { +export function getMask(picked: Feature): FeatureCollection | undefined { const diff = difference( featureCollection([ polygon([ @@ -70,10 +62,5 @@ export function setMask( } } - setData( - featureCollection([ - flattened.features.length < 2 ? picked : (union(flattened) ?? picked), - diff, - ]), - ); + return featureCollection([flattened.features.length < 2 ? picked : (union(flattened) ?? picked), diff]); } diff --git a/src/proximity.ts b/src/utils/proximity.ts similarity index 62% rename from src/proximity.ts rename to src/utils/proximity.ts index 2451e9f..eb511e8 100644 --- a/src/proximity.ts +++ b/src/utils/proximity.ts @@ -1,20 +1,10 @@ -import type { MapController, ProximityRule } from "./types"; +import type { ProximityRule } from "../types"; let cachedLocation: { time: number; coords: undefined | string } | undefined; -export async function getProximity( - mapController: MapController | undefined, - proximity: ProximityRule[] | null | undefined, - ac: AbortController, -) { - const centerAndZoom = mapController?.getCenterAndZoom(); - +export async function getProximity(centerAndZoom: [zoom: number, lon: number, lat: number] | undefined, proximity: ProximityRule[] | null | undefined, ac: AbortController) { for (const rule of proximity ?? []) { - if ( - centerAndZoom && - ((rule.minZoom != undefined && rule.minZoom > centerAndZoom[0]) || - (rule.maxZoom != undefined && rule.maxZoom < centerAndZoom[0])) - ) { + if (centerAndZoom && ((rule.minZoom != undefined && rule.minZoom > centerAndZoom[0]) || (rule.maxZoom != undefined && rule.maxZoom < centerAndZoom[0]))) { continue; } @@ -23,11 +13,7 @@ export async function getProximity( } cg: if (rule.type === "client-geolocation") { - if ( - cachedLocation && - rule.cachedLocationExpiry && - cachedLocation.time + rule.cachedLocationExpiry > Date.now() - ) { + if (cachedLocation && rule.cachedLocationExpiry && cachedLocation.time + rule.cachedLocationExpiry > Date.now()) { if (!cachedLocation.coords) { break cg; } @@ -45,13 +31,10 @@ export async function getProximity( navigator.geolocation.getCurrentPosition( (pos) => { - resolve( - [pos.coords.longitude, pos.coords.latitude] - .map((c) => c.toFixed(6)) - .join(","), - ); + resolve([pos.coords.longitude, pos.coords.latitude].map((c) => c.toFixed(6)).join(",")); }, (err) => { + // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors reject(err); }, rule, diff --git a/src/vanilla.ts b/src/vanilla.ts deleted file mode 100644 index f5f92fa..0000000 --- a/src/vanilla.ts +++ /dev/null @@ -1,166 +0,0 @@ -import GeocodingControlComponent from "./GeocodingControl.svelte"; -import type { ControlOptions, DispatcherType, MapController } from "./types"; - -const finalizationRegistry = - new FinalizationRegistry((gc) => { - gc.$destroy(); - }); - -type Options = ControlOptions & { mapController?: MapController }; - -interface GeocodingControlEvent extends CustomEvent { - readonly target: GeocodingControl; - readonly currentTarget: GeocodingControl; -} - -type CustomEventListenerOrEventListenerObject = - | ((evt: CustomEventMap[K]) => void) - | { handleEvent(object: CustomEventMap[K]): void }; - -type CustomEventMap = { - [T in keyof DispatcherType]: GeocodingControlEvent; -}; - -export class GeocodingControl extends EventTarget { - #gc: GeocodingControlComponent; - - constructor({ target, ...options }: Options & { target: HTMLElement }) { - super(); - - this.#gc = new GeocodingControlComponent({ - target, - props: options, - }); - - for (const eventName of [ - "select", - "pick", - "featureslisted", - "featuresmarked", - "response", - "optionsvisibilitychange", - "reversetoggle", - "querychange", - ] as const) { - this.#gc.$on(eventName, (event) => { - // Use the new `emit` method for type-safe dispatching - this.#emit(eventName, event.detail); - }); - } - - this.#gc.$on("select", (event) => { - const geocodingEvent = new CustomEvent(event.type, { - detail: event.detail, - }) as GeocodingControlEvent; - - this.dispatchEvent(geocodingEvent); - }); - - finalizationRegistry.register(this, this.#gc); - } - - /** - * Update the control options. - * - * @param options options to update - */ - setOptions(options: Partial) { - this.#gc.$set(options); - } - - /** - * Set the content of search input box. - * - * @param value text to set - * @param submit perform the search - */ - setQuery(value: string, submit = true) { - this.#gc?.setQuery(value, submit); - } - - /** - * Clear geocoding search results from the map. - */ - clearMap() { - this.#gc?.clearMap(); - } - - /** - * Clear search result list. - */ - clearList() { - this.#gc?.clearList(); - } - - /** - * Set reverse geocoding mode. - * - * @param reverseActive reverse geocoding active - */ - setReverseMode(reverseActive: boolean) { - this.#gc?.$set({ reverseActive }); - } - - /** - * Focus the search input box. - * - * @param options [FocusOptions](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus#options) - */ - focus(options?: FocusOptions) { - this.#gc?.focus(options); - } - - /** - * Blur the search input box. - */ - blur() { - this.#gc?.blur(); - } - - addEventListener( - type: K, - callback: CustomEventListenerOrEventListenerObject | null, - options?: AddEventListenerOptions | boolean, - ): void; - - addEventListener( - type: string, - callback: EventListenerOrEventListenerObject | null, - options?: AddEventListenerOptions | boolean, - ): void { - super.addEventListener(type, callback, options); - } - - removeEventListener( - type: K, - callback: CustomEventListenerOrEventListenerObject | null, - options?: EventListenerOptions | boolean, - ): void; - - removeEventListener( - type: string, - callback: EventListenerOrEventListenerObject | null, - options?: EventListenerOptions | boolean, - ): void { - super.removeEventListener(type, callback, options); - } - - dispatchEvent( - event: CustomEventMap[K], - ): boolean; - - dispatchEvent(event: Event): boolean { - return super.dispatchEvent(event); - } - - #emit( - type: K, - detail: CustomEventMap[K]["detail"], - ): boolean { - return super.dispatchEvent( - new CustomEvent(type, { - detail, - }) as GeocodingControlEvent, - ); - } -} diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index 4078e74..cf6801c 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -1,2 +1,6 @@ -/// /// + +interface ImportMetaEnv { + VITE_API_URL: string; + VITE_LIB_VERSION: string; +} diff --git a/svelte.config.js b/svelte.config.js deleted file mode 100644 index 7714a51..0000000 --- a/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import sveltePreprocess from "svelte-preprocess"; - -export default { - // Consult https://github.com/sveltejs/svelte-preprocess - // for more information about preprocessors - preprocess: sveltePreprocess(), -}; diff --git a/sync-info.js b/sync-info.js deleted file mode 100644 index d7b8012..0000000 --- a/sync-info.js +++ /dev/null @@ -1,21 +0,0 @@ -import fs from "fs"; -import path from "path"; -import { argv } from "process"; - -export function syncInfo() { - const packageJson = JSON.parse( - fs.readFileSync(path.resolve(import.meta.dirname, "package.json"), "utf-8"), - ); - - fs.writeFileSync( - path.resolve(import.meta.dirname, "src/info.json"), - JSON.stringify({ - name: packageJson.name, - version: packageJson.version, - }), - ); -} - -if (argv[2] === "run") { - syncInfo(); -} diff --git a/test/geocoder.test.ts b/test/geocoder.test.ts new file mode 100644 index 0000000..61ab753 --- /dev/null +++ b/test/geocoder.test.ts @@ -0,0 +1,509 @@ +/* eslint-disable + @typescript-eslint/no-non-null-assertion, + @typescript-eslint/no-unsafe-assignment, + @typescript-eslint/unbound-method, +*/ + +vi.mock("../src/utils/proximity", () => ({ + getProximity: () => Promise.resolve(undefined), +})); + +import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import "../src"; + +const wait = (ms = 0) => new Promise((res) => setTimeout(res, ms)); + +const features = [ + { + type: "Feature", + properties: { + ref: "osm:r436057", + country_code: "cz", + wikidata: "Q110206380", + kind: "admin_area", + }, + geometry: { + type: "Point", + coordinates: [16.469106609414666, 49.75598483456225], + }, + bbox: [16.465552747249603, 49.754559553925084, 16.473205089569092, 49.75747784699889], + center: [16.469106609414666, 49.75598483456225], + place_name: "Svitavy-město, Svitavy, Česko", + place_type: ["locality"], + relevance: 0.96, + id: "locality.11077", + }, + { + type: "Feature", + properties: { + ref: "osm:r430594", + country_code: "cz", + wikidata: "Q110206383", + kind: "admin_area", + }, + geometry: { + type: "Point", + coordinates: [16.465495476625506, 49.76117914674463], + }, + bbox: [16.428668349981308, 49.75038855709432, 16.507942378520966, 49.77617713549572], + center: [16.465495476625506, 49.76117914674463], + place_name: "Svitavy-předměstí, Svitavy, Česko", + place_type: ["locality"], + relevance: 0.96, + id: "locality.15996", + }, + { + type: "Feature", + properties: { + ref: "osm:r434306", + country_code: "cz", + wikidata: "Q110699144", + kind: "admin_area", + }, + geometry: { + type: "Point", + coordinates: [14.62416868785067, 50.73106309665621], + }, + bbox: [14.607590585947039, 50.72036776932437, 14.64605715125799, 50.744104683541444], + center: [14.62416868785067, 50.73106309665621], + place_name: "Svitava, Cvikov, Česko", + place_type: ["locality"], + relevance: 0.891429, + id: "locality.3801", + place_type_name: ["katastrální území"], + }, + { + type: "Feature", + properties: { + ref: "osm:r435261", + country_code: "cz", + wikidata: "Q110208405", + kind: "admin_area", + place_type_name: ["katastrální území"], + }, + geometry: { + type: "Point", + coordinates: [16.53300641661326, 49.70491448400361], + }, + bbox: [16.493744775652885, 49.67049579549808, 16.577192656695843, 49.72413044651795], + center: [16.53300641661326, 49.70491448400361], + place_name: "Sklené u Svitav, Sklené, Česko", + place_type: ["locality"], + relevance: 0.356571, + id: "locality.8864", + text: "Sklené u Svitav", + place_type_name: ["katastrální území"], + }, + { + type: "Feature", + properties: { + ref: "osm:r428919", + country_code: "cz", + wikidata: "Q110206476", + kind: "admin_area", + place_type_name: ["katastrální území"], + }, + geometry: { + type: "Point", + coordinates: [16.541825964537338, 49.79862593521514], + }, + bbox: [16.504300273954872, 49.77947603194767, 16.573985069990158, 49.82171244263241], + center: [16.541825964537338, 49.79862593521514], + place_name: "Dětřichov u Svitav, Dětřichov, Česko", + place_type: ["locality"], + relevance: 0.356571, + id: "locality.12692", + place_type_name: ["katastrální území"], + }, +]; + +describe("standalone control", () => { + const fetchMock = vi.fn(() => { + return Promise.resolve({ + ok: true, + text: () => Promise.resolve(""), + json: () => + Promise.resolve({ + type: "FeatureCollection", + features, + query: ["svitavy"], + }), + }); + }); + + beforeAll(() => { + vi.stubGlobal("fetch", fetchMock); + }); + + beforeEach(() => { + vi.clearAllMocks(); + }); + + afterEach(() => { + document.body.replaceChildren(); + }); + + afterAll(() => { + vi.unstubAllGlobals(); + }); + + it("should be registered as a webcomponent", () => { + expect(customElements.get("maptiler-geocoder")).toBeTruthy(); + }); + + it("should have custom methods", () => { + const element = document.createElement("maptiler-geocoder"); + + expect(element.setOptions).toBeTruthy(); + expect(element.setQuery).toBeTruthy(); + expect(element.submitQuery).toBeTruthy(); + expect(element.clearList).toBeTruthy(); + }); + + it("should focus input element when focus method called", async () => { + const element = document.createElement("maptiler-geocoder"); + document.body.append(element as Node); + await wait(); + + element.focus(); + expect(document.activeElement?.localName).toBe("maptiler-geocoder"); + expect(element.shadowRoot!.activeElement?.localName).toBe("input"); + }); + + it("should call API when submitted programmatically", async () => { + vi.stubGlobal("fetch", fetchMock); + + const element = document.createElement("maptiler-geocoder"); + + element.submitQuery("svitavy"); + await wait(); + + expect(fetch).toHaveBeenCalledOnce(); + expect(fetchMock.mock.calls[0]).toEqual([expect.stringContaining("svitavy"), expect.any(Object)]); + }); + + it("should call API when submitted from input element", async () => { + const element = document.createElement("maptiler-geocoder"); + document.body.append(element as Node); + await wait(); + + element.shadowRoot!.querySelector("input")!.value = "svitavy"; + element.shadowRoot!.querySelector("input")!.dispatchEvent(new Event("input")); + element.shadowRoot!.querySelector("form")!.dispatchEvent(new Event("submit")); + await wait(); + + expect(fetch).toHaveBeenCalledOnce(); + expect(fetchMock.mock.calls[0]).toEqual([expect.stringContaining("svitavy"), expect.any(Object)]); + }); + + it("should call API after debounce when input value changes", async () => { + const element = document.createElement("maptiler-geocoder"); + document.body.append(element as Node); + await wait(); + + element.shadowRoot!.querySelector("input")!.value = "svitavy"; + element.shadowRoot!.querySelector("input")!.dispatchEvent(new Event("input")); + + expect(fetch).not.toHaveBeenCalled(); + + await wait(200); // debounce + + expect(fetch).toHaveBeenCalledOnce(); + expect(fetchMock.mock.calls[0]).toEqual([expect.stringContaining("svitavy"), expect.any(Object)]); + }); + + it("should call API after debounce when query changes programmatically", async () => { + const element = document.createElement("maptiler-geocoder"); + document.body.append(element as Node); + await wait(); + + element.setQuery("svitavy"); + + expect(fetch).not.toHaveBeenCalled(); + + await wait(200); // debounce + + expect(fetch).toHaveBeenCalledOnce(); + expect(fetchMock.mock.calls[0]).toEqual([expect.stringContaining("svitavy"), expect.any(Object)]); + }); + + it("should not call API when input value changes if showResultsWhileTyping is false", async () => { + const element = document.createElement("maptiler-geocoder"); + element.showResultsWhileTyping = false; + document.body.append(element as Node); + await wait(); + + element.shadowRoot!.querySelector("input")!.value = "svitavy"; + element.shadowRoot!.querySelector("input")!.dispatchEvent(new Event("input")); + + expect(fetch).not.toHaveBeenCalled(); + + await wait(200 + 50); // debounce + extra time + + expect(fetch).not.toHaveBeenCalled(); + }); + + it("should not call API when query changes programmatically if showResultsWhileTyping is false", async () => { + const element = document.createElement("maptiler-geocoder"); + element.showResultsWhileTyping = false; + document.body.append(element as Node); + await wait(); + + element.setQuery("svitavy"); + + expect(fetch).not.toHaveBeenCalled(); + + await wait(200 + 50); // debounce + extra time + + expect(fetch).not.toHaveBeenCalled(); + }); + + it("should dispatch reversetoggle event when reverse button is clicked", async () => { + const listener = vi.fn(); + const element = document.createElement("maptiler-geocoder"); + element.enableReverse = "button"; + element.addEventListener("reversetoggle", listener); + document.body.append(element as Node); + await wait(); + + element.shadowRoot!.querySelector("maptiler-geocode-reverse-geocoding-icon")!.parentElement!.dispatchEvent(new Event("click")); + await wait(); + + expect(listener).toHaveBeenCalledOnce(); + expect(listener).toHaveBeenLastCalledWith(expect.objectContaining({ detail: { reverse: true } })); + + element.shadowRoot!.querySelector("maptiler-geocode-reverse-geocoding-icon")!.parentElement!.dispatchEvent(new Event("click")); + await wait(); + + expect(listener).toHaveBeenCalledTimes(2); + expect(listener).toHaveBeenLastCalledWith(expect.objectContaining({ detail: { reverse: false } })); + }); + + it("should dispatch querychange event when query changes programmatically", async () => { + const listener = vi.fn(); + const element = document.createElement("maptiler-geocoder"); + element.addEventListener("querychange", listener); + document.body.append(element as Node); + await wait(); + + element.setQuery("svitavy"); + + expect(listener).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({ detail: { query: "svitavy", reverseCoords: false } })); + }); + + it("should dispatch querychange event when query changes by user", async () => { + const listener = vi.fn(); + const element = document.createElement("maptiler-geocoder"); + element.addEventListener("querychange", listener); + document.body.append(element as Node); + await wait(); + + element.shadowRoot!.querySelector("input")!.value = "svitavy"; + element.shadowRoot!.querySelector("input")!.dispatchEvent(new Event("input")); + + expect(listener).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({ detail: { query: "svitavy", reverseCoords: false } })); + }); + + it("should dispatch queryclear event when clear button is clicked", async () => { + const listener = vi.fn(); + const element = document.createElement("maptiler-geocoder"); + element.addEventListener("queryclear", listener); + document.body.append(element as Node); + await wait(); + + element.shadowRoot!.querySelector("maptiler-geocode-clear-icon")!.parentElement!.dispatchEvent(new Event("click")); + + expect(listener).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({ detail: null })); + }); + + it("should dispatch request event when API request is dispatched", async () => { + const listener = vi.fn(); + const element = document.createElement("maptiler-geocoder"); + element.addEventListener("request", listener); + document.body.append(element as Node); + await wait(); + + element.submitQuery("svitavy"); + await wait(); + + expect(listener).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({ detail: { urlObj: expect.any(URL) } })); + }); + + it("should dispatch response event when API request finishes", async () => { + const listener = vi.fn(); + const element = document.createElement("maptiler-geocoder"); + element.addEventListener("response", listener); + document.body.append(element as Node); + await wait(); + + element.submitQuery("svitavy"); + await wait(); + + expect(listener).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({ detail: { featureCollection: expect.any(Object), url: expect.any(String) } })); + }); + + it("should dispatch select event when first feature is selected automatically", async () => { + const listener = vi.fn(); + const element = document.createElement("maptiler-geocoder"); + element.addEventListener("select", listener); + document.body.append(element as Node); + await wait(); + + element.setQuery("svitavy"); + await wait(200); // debounce + + expect(listener).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({ detail: { feature: features[0] } })); + }); + + it("should dispatch select event when a feature is selected with mouse", async () => { + const listener = vi.fn(); + const element = document.createElement("maptiler-geocoder"); + element.addEventListener("select", listener); + document.body.append(element as Node); + await wait(); + + element.setQuery("svitavy"); + await wait(200); // debounce + + element.shadowRoot!.querySelector("feature-item:nth-child(3)")!.dispatchEvent(new Event("mouseenter")); + await wait(); + + expect(listener).toHaveBeenCalledTimes(2); + expect(listener).toHaveBeenLastCalledWith(expect.objectContaining({ detail: { feature: features[2] } })); + }); + + it("should dispatch select event when a feature is selected with keyboard", async () => { + const listener = vi.fn(); + const element = document.createElement("maptiler-geocoder"); + element.addEventListener("select", listener); + document.body.append(element as Node); + await wait(); + + element.setQuery("svitavy"); + await wait(200); // debounce + + element.shadowRoot!.querySelector("input")!.dispatchEvent(new KeyboardEvent("keydown", { key: "ArrowDown" })); + await wait(); + + expect(listener).toHaveBeenCalledTimes(2); + expect(listener).toHaveBeenLastCalledWith(expect.objectContaining({ detail: { feature: features[1] } })); + }); + + it("should dispatch pick event when a feature is picked with mouse", async () => { + const listener = vi.fn(); + const element = document.createElement("maptiler-geocoder"); + element.addEventListener("pick", listener); + document.body.append(element as Node); + await wait(); + + element.setQuery("svitavy"); + await wait(200); // debounce + + element.shadowRoot!.querySelector("feature-item:nth-child(3)")!.dispatchEvent(new Event("click")); + await wait(); + + expect(listener).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({ detail: { feature: features[2] } })); + }); + + it("should dispatch pick event when a feature is picked with keyboard", async () => { + const listener = vi.fn(); + const element = document.createElement("maptiler-geocoder"); + element.addEventListener("pick", listener); + document.body.append(element as Node); + await wait(); + + element.setQuery("svitavy"); + await wait(200); // debounce + + element.shadowRoot!.querySelector("input")!.dispatchEvent(new KeyboardEvent("keydown", { key: "ArrowDown" })); + element.shadowRoot!.querySelector("form")!.dispatchEvent(new Event("submit")); + await wait(); + + expect(listener).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({ detail: { feature: features[1] } })); + }); + + it("should dispatch featuresshow event when list of features is visible in DOM", async () => { + const listener = vi.fn(); + const element = document.createElement("maptiler-geocoder"); + element.addEventListener("featuresshow", listener); + document.body.append(element as Node); + await wait(); + + element.setQuery("svitavy"); + await wait(200); // debounce + + expect(listener).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({ detail: null })); + expect(element.shadowRoot!.querySelectorAll("feature-item").length).not.toBe(0); + }); + + it("should dispatch featureshide event when list of features is removed from DOM", async () => { + const listener = vi.fn(); + const element = document.createElement("maptiler-geocoder"); + element.addEventListener("featureshide", listener); + document.body.append(element as Node); + await wait(); + + element.setQuery("svitavy"); + await wait(200); // debounce + + element.clearList(); + await wait(); + + expect(listener).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({ detail: null })); + expect(element.shadowRoot!.querySelectorAll("feature-item").length).toBe(0); + }); + + it("should dispatch featureslisted event when list of features is loaded from API", async () => { + const listener = vi.fn(); + const element = document.createElement("maptiler-geocoder"); + element.addEventListener("featureslisted", listener); + document.body.append(element as Node); + await wait(); + + element.setQuery("svitavy"); + await wait(200); // debounce + + expect(listener).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({ detail: { features } })); + }); + + it("should dispatch featuresclear event when list of features is forgotten", async () => { + const listener = vi.fn(); + const element = document.createElement("maptiler-geocoder"); + element.addEventListener("featuresclear", listener); + document.body.append(element as Node); + await wait(); + + element.setQuery("svitavy"); + await wait(200); // debounce + + element.clearList(); + await wait(); + + expect(listener).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({ detail: null })); + }); + + it("should dispatch focusin event when input is focused", async () => { + const listener = vi.fn(); + const element = document.createElement("maptiler-geocoder"); + element.addEventListener("focusin", listener); + document.body.append(element as Node); + await wait(); + + element.focus(); + + expect(listener).toHaveBeenCalledExactlyOnceWith(expect.any(FocusEvent)); + }); + + it("should dispatch focusout event when input loses focus", async () => { + const listener = vi.fn(); + const element = document.createElement("maptiler-geocoder"); + element.addEventListener("focusout", listener); + document.body.append(element as Node); + await wait(); + + element.focus(); + document.body.focus(); + + expect(listener).toHaveBeenCalledExactlyOnceWith(expect.any(FocusEvent)); + }); +}); diff --git a/test/maptiler-control.test.ts b/test/maptiler-control.test.ts new file mode 100644 index 0000000..b860b08 --- /dev/null +++ b/test/maptiler-control.test.ts @@ -0,0 +1,176 @@ +/* eslint-disable + @typescript-eslint/no-empty-function, + @typescript-eslint/no-explicit-any, + @typescript-eslint/no-non-null-assertion, + @typescript-eslint/no-unsafe-assignment, + @typescript-eslint/no-unsafe-return, +*/ + +globalThis.WebGL2RenderingContext = class WebGL2RenderingContextMock { + activeTexture = () => {}; + attachShader = () => {}; + bindAttribLocation = () => {}; + bindBuffer = () => {}; + bindFramebuffer = () => {}; + blendColor = () => {}; + blendEquation = () => {}; + blendFunc = () => {}; + bufferData = () => {}; + clear = () => {}; + clearColor = () => {}; + clearDepth = () => {}; + clearStencil = () => {}; + colorMask = () => {}; + compileShader = () => {}; + createBuffer = () => {}; + createProgram = () => {}; + createShader = () => {}; + cullFace = () => {}; + deleteShader = () => {}; + depthFunc = () => {}; + depthMask = () => {}; + depthRange = () => {}; + disable = () => {}; + drawElements = () => {}; + enable = () => {}; + enableVertexAttribArray = () => {}; + frontFace = () => {}; + getExtension = () => {}; + getParameter = () => {}; + getProgramParameter = () => true; + getShaderParameter = () => true; + getUniformLocation = () => {}; + isContextLost = () => {}; + linkProgram = () => {}; + pixelStorei = () => {}; + shaderSource = () => {}; + stencilFunc = () => {}; + stencilMask = () => {}; + stencilOp = () => {}; + uniform1f = () => {}; + uniform2f = () => {}; + uniform4f = () => {}; + uniformMatrix4fv = () => {}; + useProgram = () => {}; + vertexAttribPointer = () => {}; + viewport = () => {}; +} as any; +globalThis.HTMLCanvasElement.prototype.getContext = () => new WebGL2RenderingContext() as any; + +import { Map as SDKMap } from "@maptiler/sdk"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { MaplibreglGeocodingControl, type MaplibreglGeocodingControlOptions } from "../src/maplibregl"; + +const wait = (ms = 0) => new Promise((res) => setTimeout(res, ms)); + +describe("MaplibreglGeocodingControl", () => { + function createMapHelper(controlOptions?: MaplibreglGeocodingControlOptions) { + const container = document.createElement("div"); + document.body.appendChild(container); + const map = new SDKMap({ + container, + style: { + version: 8, + sources: {}, + layers: [], + }, + }); + const control = new MaplibreglGeocodingControl(controlOptions); + map.addControl(control); + const element = container.querySelector("maptiler-geocoder")!; + return { + container, + map, + control, + element, + }; + } + + beforeEach(() => { + vi.clearAllMocks(); + }); + + afterEach(() => { + document.body.replaceChildren(); + }); + + it("should instantiate the control", () => { + expect(() => { + new MaplibreglGeocodingControl(); + }).not.toThrow(); + }); + + it("should move the element into the map DOM", () => { + const { container } = createMapHelper(); + + expect(container.querySelector("maptiler-geocoder")).not.toBeNull(); + }); + + it("should propagate geocoder options into the geocoder component", () => { + const { element } = createMapHelper({ limit: 10 }); + + expect(element.limit).toBe(10); + }); + + it("should not propagate control-specific options into the geocoder component", () => { + const { element } = createMapHelper({ flyToSelected: true }); + + expect(element).not.toHaveProperty("flyToSelected"); + }); + + it("should set value of geocoder input when setQuery is called", async () => { + const { control, element } = createMapHelper({ limit: 10 }); + + control.setQuery("svitavy"); + await wait(); + + expect(element.shadowRoot!.querySelector("input")!.value).toBe("svitavy"); + }); + + it("should focus the geocoder input when focus is called", async () => { + const { control, element } = createMapHelper({ limit: 10 }); + await wait(); + + control.focus(); + + expect(document.activeElement!.localName).toBe("maptiler-geocoder"); + expect(element.shadowRoot!.activeElement!.localName).toBe("input"); + }); + + it("should unfocus the geocoder input when blur is called", async () => { + const { control, element } = createMapHelper({ limit: 10 }); + await wait(); + + control.focus(); + control.blur(); + + expect(document.activeElement!.localName).not.toBe("maptiler-geocoder"); + expect(element.shadowRoot!.activeElement).toBeNullable(); + }); + + it("should forward DOM events from the geocoder component as Evented events", () => { + const { control, element } = createMapHelper({ limit: 10 }); + + const querychangeListener = vi.fn(); + const selectListener = vi.fn(); + const pickListener = vi.fn(); + const featureslistedListener = vi.fn(); + + control.on("querychange", querychangeListener); + control.on("select", selectListener); + control.on("pick", pickListener); + control.on("featureslisted", featureslistedListener); + + element.dispatchEvent(new CustomEvent("querychange", { detail: { query: "svitavy" } })); + expect(querychangeListener).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({ query: "svitavy" })); + + element.dispatchEvent(new CustomEvent("select", { detail: { feature: { name: "Svitavy" } } })); + expect(selectListener).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({ feature: { name: "Svitavy" } })); + + element.dispatchEvent(new CustomEvent("pick", { detail: { feature: { name: "Svitavy" } } })); + expect(pickListener).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({ feature: { name: "Svitavy" } })); + + element.dispatchEvent(new CustomEvent("featureslisted", { detail: { features: [] } })); + expect(featureslistedListener).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({ features: [] })); + }); +}); diff --git a/tsconfig.dist.json b/tsconfig.dist.json deleted file mode 100644 index 99556f7..0000000 --- a/tsconfig.dist.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "baseUrl": ".", - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "strict": true, - "moduleResolution": "Node", - "resolveJsonModule": true - }, - "include": ["src/*.d.ts", "src/*.ts", "src/*.js", "src/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/tsconfig.json b/tsconfig.json index 314807a..4aff1b1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,17 +1,28 @@ { - "extends": "./tsconfig.dist.json", "compilerOptions": { - "jsx": "react-jsx" + "baseUrl": "src", + "moduleResolution": "Node", + "target": "es2021", + "experimentalDecorators": true, + "useDefineForClassFields": false, + "module": "ESNext", + "lib": ["es2021", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + "jsx": "react-jsx", + /* Bundler mode */ + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "declaration": true, + "erasableSyntaxOnly": true, + "allowSyntheticDefaultImports": true, + "allowJs": true }, - "include": [ - "src/*.d.ts", - "src/*.ts", - "src/*.js", - "src/*.svelte", - "examples/**/*.d.ts", - "examples/**/*.ts", - "examples/**/*.tsx", - "examples/**/*.js", - "examples/**/*.svelte" - ] + "exclude": ["dist"], + "include": ["vite.config.ts", "vite.config-dev.ts", "vite.config-test.ts", "vitest-setup-tests.ts", "src", "demos", "test"] } diff --git a/tsconfig.node.json b/tsconfig.node.json deleted file mode 100644 index 65dbdb9..0000000 --- a/tsconfig.node.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "module": "ESNext", - "moduleResolution": "Node" - }, - "include": ["vite.config.ts"] -} diff --git a/vite.config-dev.ts b/vite.config-dev.ts new file mode 100644 index 0000000..47a4939 --- /dev/null +++ b/vite.config-dev.ts @@ -0,0 +1,90 @@ +import { readdirSync } from "node:fs"; +import { resolve } from "node:path"; +import { defineConfig } from "vite"; +import { viteStaticCopy } from "vite-plugin-static-copy"; +import packagejson from "./package.json"; + +function green(text: string) { + return `\x1b[32m${text}\x1b[0m`; +} + +function yellow(text: string) { + return `\x1b[33m${text}\x1b[0m`; +} + +function d(text: string) { + return `\x1b[0m${text}\x1b[0m`; +} + +function purple(text: string) { + return `\x1b[35m${text}\x1b[0m`; +} + +function centerText(text: string, lineLength: number) { + // strip ansi codes from the text + const stripped = text.replace(/\x1b\[[0-9;]*m/g, ""); + const ansiCodes = text.match(/\x1b\[[0-9;]*m/g) || []; + const diff = lineLength - stripped.length; + const leftPadding = Math.floor(diff / 2); + const rightPadding = diff - leftPadding; + const left = " ".repeat(leftPadding); + const right = " ".repeat(rightPadding - 1); + return `${left}${ansiCodes}${text}${right}`; +} + +const entrypoints = readdirSync(resolve(__dirname, "demos")).filter((file) => file.endsWith(".html")); + +export default defineConfig({ + mode: "development", + root: "./demos", + build: { + minify: false, + sourcemap: true, + rollupOptions: { + input: entrypoints.map((file) => `./demos/${file}`), + }, + }, + define: { + __MT_SDK_VERSION__: JSON.stringify(packagejson.version), + __MT_NODE_ENV__: JSON.stringify(process.env.NODE_ENV), + }, + plugins: [ + viteStaticCopy({ + targets: [{ src: "../public/icons", dest: "assets" }], + }), + { + name: "url-override", + /** + * Changing logged URLs to include the path to the demo directory. + */ + configureServer: (server) => { + const port = server.config.server.port; + const urls = entrypoints + .map((entry) => { + return `http://localhost:${port}/${entry === "index.html" ? "" : entry}`; + }) + .sort(); + const lineLength = Math.max(...urls.map((entry) => entry.length)) + 4; + console.log("\n"); + console.log("┏" + "━".repeat(lineLength) + "┓"); + console.info(`┃` + " ".repeat(lineLength) + "┃"); + console.info("┃" + yellow(centerText(`** MapTiler Geocoding Control **`, lineLength)) + " ┃"); + console.info("┃" + purple(centerText(`** Demos **`, lineLength)) + " ┃"); + console.info(`┃` + " ".repeat(lineLength) + "┃"); + urls + .map((entry) => { + return `${d("┃")} - ${entry}`; + }, []) + .forEach((entry, _, arr) => { + const numCharactersToPad = Math.max(...arr.map((entry) => entry.length)) - entry.length; + const padding = " ".repeat(numCharactersToPad); + const output = green(entry) + padding + " ┃"; + console.log(output); + }); + console.log("┗" + "━".repeat(lineLength) + "┛"); + + console.log("\n"); + }, + }, + ], +}); diff --git a/vite.config-test.ts b/vite.config-test.ts new file mode 100644 index 0000000..3b2c74e --- /dev/null +++ b/vite.config-test.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + include: ["test/**/*.test.ts"], + typecheck: { + tsconfig: "./tsconfig.json", + }, + environment: "happy-dom", + globals: true, + setupFiles: ["@vitest/web-worker", "./vitest-setup-tests.ts"], + }, +}); diff --git a/vite.config.ts b/vite.config.ts index 40e2d00..0f866c6 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,128 +1,81 @@ -import { svelte } from "@sveltejs/vite-plugin-svelte"; import process from "node:process"; -import { sveltePreprocess } from "svelte-preprocess"; -import { BuildOptions, defineConfig } from "vite"; -import { syncInfo } from "./sync-info"; +import { type GlobalsOption } from "rollup"; +import { defineConfig, type LibraryOptions } from "vite"; +import dts from "vite-plugin-dts"; +import { externalizeDeps } from "vite-plugin-externalize-deps"; -const libs = { - leaflet: { - fileName: "leaflet", - entry: ["src/leaflet.ts"], - name: "leafletMaptilerGeocoder", +const umd = process.env.MODE === "umd"; + +const flavours: Record = { + index: { + fileName: "index", + entry: ["src/index.ts"], + name: "maptilerGeocoder", + globals: {}, }, - maplibre: { + // leaflet: { + // fileName: "leaflet", + // entry: ["src/leaflet.ts"], + // name: "maptilerGeocoder", + // globals: { + // leaflet: "L", + // }, + // }, + maplibregl: { fileName: "maplibregl", entry: ["src/maplibregl.ts"], - name: "maplibreglMaptilerGeocoder", + name: "maptilerGeocoder", + globals: { + "maplibre-gl": "maplibregl", + }, }, maptilersdk: { fileName: "maptilersdk", entry: ["src/maptilersdk.ts"], - name: "maptilersdkMaptilerGeocoder", + name: "maptilerGeocoder", + globals: { + // replace MapLibre with MapTiler SDK + "maplibre-gl": "maptilersdk", + "@maptiler/sdk": "maptilersdk", + }, }, openlayers: { fileName: "openlayers", entry: ["src/openlayers.ts"], - name: "openlayersMaptilerGeocoder", - }, - react: { - fileName: "react", - entry: ["src/react.ts"], - name: "reactMaptilerGeocoder", - }, - vanilla: { - fileName: "vanilla", - entry: ["src/vanilla.ts"], name: "maptilerGeocoder", - }, - "leaflet-controller": { - fileName: "leaflet-controller", - entry: ["src/leaflet-controller.ts"], - name: "leafletMaptilerGeocodingController", - }, - "maplibregl-controller": { - fileName: "maplibregl-controller", - entry: ["src/maplibregl-controller.ts"], - name: "maplibreglMaptilerGeocodingController", - }, - "openlayers-controller": { - fileName: "openlayers-controller", - entry: ["src/openlayers-controller.ts"], - name: "openlayersMaptilerGeocodingController", + globals: (name) => (name.startsWith("ol") ? name.replaceAll("/", ".") : ""), }, }; -let lib: BuildOptions["lib"]; +const flavour = flavours[process.env.FLAVOUR!] ?? flavours.standalone; -let rollupOptions: BuildOptions["rollupOptions"]; - -const flavour = process.env.FLAVOUR; - -if (flavour) { - if (!(flavour in libs)) { - throw new Error("invalid FLAVOUR"); - } - - lib = libs[flavour as keyof typeof libs]; - - rollupOptions = { - external: [ - "@maptiler/sdk", - "maplibre-gl", - "leaflet", - "react", - "react-dom", - /^ol(\/.*)?/, - ], - output: [ - { - format: "es", - entryFileNames: "[name].js", - chunkFileNames: "[name].js", - assetFileNames: "[name].[ext]", - }, - { - name: lib.name, - format: "umd", - entryFileNames: "[name].umd.js", - chunkFileNames: "[name].umd.js", - assetFileNames: "[name].[ext]", - - // Provide global variables to use in the UMD build for externalized deps - globals(name) { - const global = { - "@maptiler/sdk": "maptilersdk", - "maplibre-gl": "maplibregl", - leaflet: "L", - react: "React", - "react-dom": "ReactDOM", - }[name]; - - return ( - global ?? (name.startsWith("ol") ? name.replace(/\//g, ".") : "") - ); - }, - }, - ], - }; -} - -// https://vitejs.dev/config/ export default defineConfig({ - plugins: [ - { - name: "sync-info", - buildStart: syncInfo, - }, - svelte({ - preprocess: sveltePreprocess(), - }), - ], + plugins: [externalizeDeps({ deps: !umd }), umd ? undefined : dts({ exclude: ["demos"] })], publicDir: "public", build: { sourcemap: true, emptyOutDir: false, - lib, - rollupOptions, + lib: flavour, + rollupOptions: { + output: [ + umd + ? { + name: flavour.name, + format: "umd", + entryFileNames: "[name].umd.js", + chunkFileNames: "[name].umd.js", + assetFileNames: "[name].[ext]", + + // Provide global variables to use in the UMD build for externalized deps + globals: flavour.globals, + } + : { + format: "es", + entryFileNames: "[name].js", + chunkFileNames: "[name].js", + assetFileNames: "[name].[ext]", + }, + ], + }, }, }); diff --git a/vitest-setup-tests.ts b/vitest-setup-tests.ts new file mode 100644 index 0000000..959b2b5 --- /dev/null +++ b/vitest-setup-tests.ts @@ -0,0 +1,3 @@ +import ImageData from "@canvas/image-data"; +// @ts-expect-error: Global type missing +global.ImageData = ImageData;