From b1c7582c18d238a7d735e2c7747dd435585ffa82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matheus=20Vila=C3=A7a=20de=20Jesus?= Date: Sun, 25 Oct 2026 11:10:07 -0300 Subject: [PATCH 1/3] chore: start #601 From d554b199f0262046753dce7b8892f3a69d965ae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matheus=20Vila=C3=A7a=20de=20Jesus?= Date: Sun, 25 Oct 2026 11:20:43 -0300 Subject: [PATCH 2/3] fix: map: MapStage on maplibre-gl 6 through deck.gl MapLibreOverlay --- .agents/skills/codeatlas-ui/API.md | 2 +- .changeset/map-maplibre-5.md | 5 --- .changeset/map-maplibre-6.md | 5 +++ bun.lock | 32 ++++++++++--------- packages/ui/package.json | 11 +++++-- packages/ui/scripts/size-limit.ts | 2 +- packages/ui/src/lib/map/MapStage.svelte | 4 +-- packages/ui/src/lib/map/MapStage.test.svelte | 6 +++- packages/ui/src/lib/map/index.ts | 2 +- packages/ui/src/lib/map/loader.ts | 27 +++++++++++----- packages/ui/vite.config.ts | 4 ++- site/package.json | 3 +- site/public/api/v1/en/e/800.txt | 5 +++ site/public/gallery/800.md | 5 +++ .../content/docs/getting-started/choosing.mdx | 2 +- .../content/docs/getting-started/recipes.mdx | 4 +-- site/src/content/docs/map/index.mdx | 8 +++-- site/src/demos/map/stage/ThemedMap.svelte | 5 +++ 18 files changed, 87 insertions(+), 45 deletions(-) delete mode 100644 .changeset/map-maplibre-5.md create mode 100644 .changeset/map-maplibre-6.md diff --git a/.agents/skills/codeatlas-ui/API.md b/.agents/skills/codeatlas-ui/API.md index 28608b46..47cea31e 100644 --- a/.agents/skills/codeatlas-ui/API.md +++ b/.agents/skills/codeatlas-ui/API.md @@ -2025,7 +2025,7 @@ Variables: `--ca-map-bearing` | `engine?` | `"maplibre" \| "mapbox"` | `'maplibre'` | `"maplibre"` (default, no token) or `"mapbox"` (needs `accessToken`). The matching package is a peer you install. | | `accessToken?` | `string` | | Mapbox access token. Required for `engine="mapbox"`. | | `styles` | `MapStyles` | | Basemap style per color scheme. The map switches style when `colorScheme.resolved` changes, without being recreated. | -| `layers?` | `unknown[]` | | deck.gl layers drawn interleaved in the map. Needs `@deck.gl/core` and `@deck.gl/mapbox`. Replace the array to update. | +| `layers?` | `unknown[]` | | deck.gl layers drawn interleaved in the map. Needs `@deck.gl/core` plus `@deck.gl/maplibre` (`engine="maplibre"`) or `@deck.gl/mapbox` (`engine="mapbox"`). Replace the array to update. | | `fit?` | `MapBounds` | | Bounds to fit, with `padding`. Changing it fits again. | | `padding?` | `Partial` | | Pixels covered by UI on each side (a sidebar, a bottom sheet), kept clear when fitting. Each side defaults to the active `PageFrame`'s `stageInsets`, or 0 without one. | | `center?` | `[number, number]` | | | diff --git a/.changeset/map-maplibre-5.md b/.changeset/map-maplibre-5.md deleted file mode 100644 index c5578119..00000000 --- a/.changeset/map-maplibre-5.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@codeatlasdev/ui": patch ---- - -`@codeatlasdev/ui/map`: the `maplibre-gl` peer range is now `^5.0.0`. `@deck.gl/mapbox` 9.4 (the latest) throws `Cannot read properties of undefined (reading 'height')` on every frame when it draws into `maplibre-gl` 6, so a `MapStage` with `layers` logged hundreds of page errors there. Install `maplibre-gl@5` with `@deck.gl/*@~9.4`; the supported pair is documented on the Map page. A regression test draws a real `ScatterplotLayer` and fails on any page or console error. diff --git a/.changeset/map-maplibre-6.md b/.changeset/map-maplibre-6.md new file mode 100644 index 00000000..1b1e8879 --- /dev/null +++ b/.changeset/map-maplibre-6.md @@ -0,0 +1,5 @@ +--- +"@codeatlasdev/ui": patch +--- + +`@codeatlasdev/ui/map`: `MapStage` works with `maplibre-gl` 6, so the peer range is `^5.0.0 || ^6.0.0` again and you can take the fix for the critical attribution-sanitizer XSS in `maplibre-gl` 6.4.0 and earlier (GHSA-jrc7-96c5-q579, fixed in 6.4.1). With `engine="maplibre"` the deck.gl `layers` now go through `MapLibreOverlay` from the new optional peer `@deck.gl/maplibre` (`~9.4.0`, which supports `maplibre-gl` 4.5.1, 5 and 6) instead of `MapboxOverlay`, which throws `Cannot read properties of undefined (reading 'height')` on every frame there. `engine="mapbox"` keeps `@deck.gl/mapbox`. Install `@deck.gl/maplibre` instead of `@deck.gl/mapbox` when you use `maplibre-gl`. On `maplibre-gl` 6 the app must also call `setWorkerUrl` once (Vite: `import workerUrl from "maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url"`), as MapLibre's v6 migration guide requires for every bundler; the Map page shows it. diff --git a/bun.lock b/bun.lock index 02ec446f..faef227c 100644 --- a/bun.lock +++ b/bun.lock @@ -37,6 +37,7 @@ "@deck.gl/core": "9.4.0", "@deck.gl/layers": "9.4.0", "@deck.gl/mapbox": "9.4.0", + "@deck.gl/maplibre": "9.4.0", "@fontsource-variable/inter": "5.3.0", "@fontsource-variable/jetbrains-mono": "5.3.0", "@happy-dom/global-registrator": "21.0.1", @@ -57,7 +58,7 @@ "esbuild": "0.28.2", "happy-dom": "21.0.4", "magic-string": "1.4.3", - "maplibre-gl": "5.24.0", + "maplibre-gl": "6.16.0", "playwright": "1.64.0", "png-to-ico": "3.0.2", "shiki": "4.5.0", @@ -73,6 +74,7 @@ "peerDependencies": { "@deck.gl/core": "~9.4.0", "@deck.gl/mapbox": "~9.4.0", + "@deck.gl/maplibre": "~9.4.0", "@resvg/resvg-js": "^2.6.0", "@sveltejs/kit": "^2.12.0 || ^3.0.0", "@tanstack/svelte-table": "^9.2.4", @@ -80,7 +82,7 @@ "axe-core": "^4.0.0", "echarts": "^6.0.0", "mapbox-gl": "^3.0.0", - "maplibre-gl": "^5.0.0", + "maplibre-gl": "^5.0.0 || ^6.0.0", "png-to-ico": "^3.0.0", "shiki": "^4.0.0", "svelte": "^5.33.0", @@ -89,6 +91,7 @@ "optionalPeers": [ "@deck.gl/core", "@deck.gl/mapbox", + "@deck.gl/maplibre", "@resvg/resvg-js", "@sveltejs/kit", "@tanstack/svelte-table", @@ -113,6 +116,7 @@ "@deck.gl/core": "9.4.0", "@deck.gl/layers": "9.4.0", "@deck.gl/mapbox": "9.4.0", + "@deck.gl/maplibre": "9.4.0", "@fontsource-variable/inter": "5.3.0", "@fontsource-variable/jetbrains-mono": "5.3.0", "@lucide/svelte": "1.55.0", @@ -124,7 +128,7 @@ "echarts": "6.1.0", "gsap": "3.15.0", "lenis": "1.3.26", - "maplibre-gl": "5.24.0", + "maplibre-gl": "6.16.0", "marked": "18.1.1", "png-to-ico": "3.0.2", "shiki": "4.5.0", @@ -297,6 +301,8 @@ "@deck.gl/mapbox": ["@deck.gl/mapbox@9.4.0", "", { "dependencies": { "@math.gl/web-mercator": "^4.1.0" }, "peerDependencies": { "@deck.gl/core": "~9.4.0", "@luma.gl/core": "~9.4.0" } }, "sha512-otpLp3HgJKWl5KgeQ8J+8oraKAa/nOThtSB5w93KsZSN6Oq467o8vXaWjkas9aPOVoqHIM33GG/wCEYbPDuATQ=="], + "@deck.gl/maplibre": ["@deck.gl/maplibre@9.4.0", "", { "peerDependencies": { "@deck.gl/core": "~9.4.0", "@luma.gl/core": "~9.4.0", "maplibre-gl": "^4.5.1 || ^5.0.0 || ^6.0.0" } }, "sha512-ck7Hxzt0t9M7iVgbVwelZiuUEx+e2HtmhGyPmZulURV0Ct5QtIjDYc6SWWUYZqASQnyDiBgFVaSaA9DisU8ziw=="], + "@emmetio/abbreviation": ["@emmetio/abbreviation@2.3.3", "", { "dependencies": { "@emmetio/scanner": "^1.0.4" } }, "sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA=="], "@emmetio/css-abbreviation": ["@emmetio/css-abbreviation@2.1.8", "", { "dependencies": { "@emmetio/scanner": "^1.0.4" } }, "sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw=="], @@ -497,19 +503,17 @@ "@mapbox/tiny-sdf": ["@mapbox/tiny-sdf@2.3.0", "", {}, "sha512-gBvcNDBBB66bgQYvnaJ6Jk+VCaMmVq5+IZR2kWPisT88Z8s0kBQt6hfVi8QgRW8Vpg0UWZzBA4ZSyzHHC+VeRA=="], - "@mapbox/unitbezier": ["@mapbox/unitbezier@0.0.1", "", {}, "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw=="], - - "@mapbox/vector-tile": ["@mapbox/vector-tile@2.0.5", "", { "dependencies": { "@mapbox/point-geometry": "~1.1.0", "@types/geojson": "^7946.0.16", "pbf": "^4.0.2" } }, "sha512-pXj8m7KTsqZt+1jsE0xIpGvqTSbblfkuEJL/NJmNePMtEwxO8V3XMDo9WMSfDeqHvCtBI9Lmt4mGcGR10zecmw=="], + "@mapbox/unitbezier": ["@mapbox/unitbezier@1.0.0", "", {}, "sha512-fqd515fjBmANKGGsQ286E2Wvj/XvDFpGzwJxq4CI6jMQue6Oy04uCKp+JWKF00xRTmk6cEu1jPJ9p3xqH8YWqQ=="], - "@mapbox/whoots-js": ["@mapbox/whoots-js@3.1.0", "", {}, "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q=="], + "@mapbox/vector-tile": ["@mapbox/vector-tile@3.0.0", "", { "dependencies": { "@mapbox/point-geometry": "~1.1.0", "@types/geojson": "^7946.0.16", "pbf": "^5.0.0" } }, "sha512-Qf10S1uIHMk20ri/IVBnpS+esUEkVaR5Hftmz88jTInrpmWgPGJfPe3LVjjlE77trLx8tH6qjTG7uWH9hIq/0Q=="], "@maplibre/geojson-vt": ["@maplibre/geojson-vt@6.3.0", "", { "dependencies": { "kdbush": "^4.1.0" } }, "sha512-3Zw2jsU9pIJG3G2CQFbLjWj2MlAHodhD7cSY+15iywUuLmmkgzcKRnueVRZ4AcC/5wOtfhidcJAAzBpoBNs3Xg=="], - "@maplibre/maplibre-gl-style-spec": ["@maplibre/maplibre-gl-style-spec@24.10.0", "", { "dependencies": { "@mapbox/jsonlint-lines-primitives": "~2.0.2", "@mapbox/unitbezier": "^1.0.0", "json-stringify-pretty-compact": "^4.0.0", "minimist": "^1.2.8", "quickselect": "^3.0.0", "tinyqueue": "^3.0.0" }, "bin": { "gl-style-format": "dist/gl-style-format.mjs", "gl-style-migrate": "dist/gl-style-migrate.mjs", "gl-style-validate": "dist/gl-style-validate.mjs" } }, "sha512-lichxSiagMEBBrqHF0trtMQH9RKh+9jUlIJl0qW0QHvt2H/tbvUWdE+ZzI2Jd0/pT7j/iavLonlPu7EQ/ixTOw=="], + "@maplibre/maplibre-gl-style-spec": ["@maplibre/maplibre-gl-style-spec@26.4.4", "", { "dependencies": { "@mapbox/jsonlint-lines-primitives": "^2.0.3", "@mapbox/unitbezier": "^1.0.0", "json-stringify-pretty-compact": "^4.0.0", "minimist": "^1.2.8", "quickselect": "^3.0.0", "tinyqueue": "^3.0.0" }, "bin": { "gl-style-format": "dist/gl-style-format.mjs", "gl-style-migrate": "dist/gl-style-migrate.mjs", "gl-style-validate": "dist/gl-style-validate.mjs" } }, "sha512-hG4RZR4PBd/+6A3ODdZ3AnQRF106ZQk1y3bhwDg8bH/A4Oz2tnRUJVVWs9BZa6gXZ1d3UKe89C+Mm+olGBELvA=="], "@maplibre/mlt": ["@maplibre/mlt@1.3.0", "", { "dependencies": { "@mapbox/point-geometry": "^1.1.0" } }, "sha512-7M2O7ABM80Oi8XPkfkrjKB8mOBIxGoVgkA52Mu4RMWoBvvMdagQ522+WxVYujZsMpqIr3BpzrTbXrm4k8lCzCQ=="], - "@maplibre/vt-pbf": ["@maplibre/vt-pbf@4.3.2", "", { "dependencies": { "@mapbox/point-geometry": "^1.1.0", "@types/geojson": "^7946.0.16", "pbf": "^5.1.0" } }, "sha512-j6p0AdjvAR19Z3XaCysle7A4ZSo08tYOzxD0Y9NQylwPAkwJJeYub5b2eVucdeDh7erhv69DahoLOevDRERRUw=="], + "@maplibre/vt-pbf": ["@maplibre/vt-pbf@4.3.3", "", { "dependencies": { "@mapbox/point-geometry": "^1.1.0", "@types/geojson": "^7946.0.16", "pbf": "^5.1.2" } }, "sha512-dEe5XUd64RQbxNxy2OzIkJnwNDWjVmSXjCd0A7zLirm7QJ/WWbmtDFIkfsiM4yt1cplqzG6oSivRYeWx1SM1yg=="], "@math.gl/core": ["@math.gl/core@4.1.0", "", { "dependencies": { "@math.gl/types": "4.1.0" } }, "sha512-FrdHBCVG3QdrworwrUSzXIaK+/9OCRLscxI2OUy6sLOHyHgBMyfnEGs99/m3KNvs+95BsnQLWklVfpKfQzfwKA=="], @@ -787,6 +791,8 @@ "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="], + "bidi-js": ["bidi-js@1.1.0", "", { "dependencies": { "require-from-string": "^2.0.2" } }, "sha512-fX1Onk0tdVPC7obPWB5EbJ1z7NVhLq4m2xZLq2YXBkxzMXIGRpNMU88n0EPgWseKl12J7zXs7qrDxPK4sRs2fg=="], + "blake3-wasm": ["blake3-wasm@2.1.5", "", {}, "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g=="], "body-parser": ["body-parser@2.3.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^2.0.0", "debug": "^4.4.3", "http-errors": "^2.0.1", "iconv-lite": "^0.7.2", "on-finished": "^2.4.1", "qs": "^6.15.2", "raw-body": "^3.0.2", "type-is": "^2.1.0" } }, "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw=="], @@ -1171,7 +1177,7 @@ "magicast": ["magicast@0.5.5", "", { "dependencies": { "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7", "source-map-js": "^1.2.1" } }, "sha512-UicdXN8zQ3JHlxVq+28afMXPr1z7WNY6+7EJnzTdQWkTAlMLF5fNCCKxJHBQwGaNGR11581EiQmQzx73+MvszA=="], - "maplibre-gl": ["maplibre-gl@5.24.0", "", { "dependencies": { "@mapbox/jsonlint-lines-primitives": "^2.0.2", "@mapbox/point-geometry": "^1.1.0", "@mapbox/tiny-sdf": "^2.1.0", "@mapbox/unitbezier": "^0.0.1", "@mapbox/vector-tile": "^2.0.4", "@mapbox/whoots-js": "^3.1.0", "@maplibre/geojson-vt": "^6.1.0", "@maplibre/maplibre-gl-style-spec": "^24.8.1", "@maplibre/mlt": "^1.1.8", "@maplibre/vt-pbf": "^4.3.0", "@types/geojson": "^7946.0.16", "earcut": "^3.0.2", "gl-matrix": "^3.4.4", "kdbush": "^4.0.2", "murmurhash-js": "^1.0.0", "pbf": "^4.0.1", "potpack": "^2.1.0", "quickselect": "^3.0.0", "tinyqueue": "^3.0.0" } }, "sha512-ALyFxgtd5R+65UqZ/++lOqwWcC0SNho9c27fYSyLmG7AfnAul2o46F05aDJGPbFU57wos9dgcIySHs0Xe6ia3A=="], + "maplibre-gl": ["maplibre-gl@6.16.0", "", { "dependencies": { "@mapbox/point-geometry": "^1.1.0", "@mapbox/tiny-sdf": "^2.3.0", "@mapbox/unitbezier": "^1.0.0", "@mapbox/vector-tile": "^3.0.0", "@maplibre/geojson-vt": "^6.3.0", "@maplibre/maplibre-gl-style-spec": "^26.4.4", "@maplibre/mlt": "^1.3.0", "@maplibre/vt-pbf": "^4.3.3", "@types/geojson": "^7946.0.16", "bidi-js": "^1.1.0", "earcut": "^3.2.4", "gl-matrix": "^3.4.4", "kdbush": "^4.1.0", "murmurhash-js": "^1.0.0", "pbf": "^5.1.2", "potpack": "^2.1.0", "quickselect": "^3.0.0", "tinyqueue": "^3.0.0" } }, "sha512-gApO66EMtoDZuio680RUBvskR7ahFd/NNhLN4tBAs+Y7FeT4gQV8zVFgYVMRmFxQznOEzecW19w6xOd9XjZjiA=="], "marked": ["marked@18.1.1", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-zEGgrtUG8crk+TrMacJSVABU4DYDDkS8uqgU3ohrn/2fW9C2AEfUrO3m6IhpIpQpl7YcVpiXXC9cSMWDANT3dg=="], @@ -1277,7 +1283,7 @@ "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - "pbf": ["pbf@4.0.2", "", { "dependencies": { "resolve-protobuf-schema": "^2.1.0" }, "bin": { "pbf": "bin/pbf" } }, "sha512-J0ajxARhZfpUEebxYs1vhMGMuLSXtBe1e+fFPDrf2uA2hgo+UshKfNUWOz92HJNz6/NFEXseQPddnHkTreWRqg=="], + "pbf": ["pbf@5.1.2", "", { "dependencies": { "resolve-protobuf-schema": "^2.1.0" }, "bin": { "pbf": "bin/pbf" } }, "sha512-mnvGdvOrIvJOBGUEdGkrVXjN8E/VkIJCkf2eS1DH2yv82ORUlLttmDt0rWY38yYZmVwciZwBUvHM20qxBZf40w=="], "piccolore": ["piccolore@0.1.3", "", {}, "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw=="], @@ -1635,10 +1641,6 @@ "@formatjs/intl-localematcher/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "@maplibre/maplibre-gl-style-spec/@mapbox/unitbezier": ["@mapbox/unitbezier@1.0.0", "", {}, "sha512-fqd515fjBmANKGGsQ286E2Wvj/XvDFpGzwJxq4CI6jMQue6Oy04uCKp+JWKF00xRTmk6cEu1jPJ9p3xqH8YWqQ=="], - - "@maplibre/vt-pbf/pbf": ["pbf@5.1.2", "", { "dependencies": { "resolve-protobuf-schema": "^2.1.0" }, "bin": { "pbf": "bin/pbf" } }, "sha512-mnvGdvOrIvJOBGUEdGkrVXjN8E/VkIJCkf2eS1DH2yv82ORUlLttmDt0rWY38yYZmVwciZwBUvHM20qxBZf40w=="], - "@puppeteer/browsers/yargs": ["yargs@18.2.0", "", { "dependencies": { "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "string-width": "^8.2.1", "y18n": "^5.0.5", "yargs-parser": "^22.0.0" } }, "sha512-9OpKOLeaoNFecEp7P6iYbzze/5CqWoH7N3SMs/6y1XF4nMvFMspEGZzJ6uFi9MmQwXhyzqYoSEKO3tvA3Z/o2w=="], "@swc/helpers/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], diff --git a/packages/ui/package.json b/packages/ui/package.json index 4f4af81b..415e7b3a 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -166,6 +166,7 @@ "@deck.gl/core": "9.4.0", "@deck.gl/layers": "9.4.0", "@deck.gl/mapbox": "9.4.0", + "@deck.gl/maplibre": "9.4.0", "@fontsource-variable/inter": "5.3.0", "@fontsource-variable/jetbrains-mono": "5.3.0", "@happy-dom/global-registrator": "21.0.1", @@ -186,7 +187,7 @@ "esbuild": "0.28.2", "happy-dom": "21.0.4", "magic-string": "1.4.3", - "maplibre-gl": "5.24.0", + "maplibre-gl": "6.16.0", "playwright": "1.64.0", "png-to-ico": "3.0.2", "shiki": "4.5.0", @@ -210,10 +211,11 @@ "typescript": ">=5.0.0", "@resvg/resvg-js": "^2.6.0", "png-to-ico": "^3.0.0", - "maplibre-gl": "^5.0.0", + "maplibre-gl": "^5.0.0 || ^6.0.0", "mapbox-gl": "^3.0.0", "@deck.gl/core": "~9.4.0", - "@deck.gl/mapbox": "~9.4.0" + "@deck.gl/mapbox": "~9.4.0", + "@deck.gl/maplibre": "~9.4.0" }, "publishConfig": { "registry": "https://registry.npmjs.org", @@ -258,6 +260,9 @@ }, "@deck.gl/mapbox": { "optional": true + }, + "@deck.gl/maplibre": { + "optional": true } } } diff --git a/packages/ui/scripts/size-limit.ts b/packages/ui/scripts/size-limit.ts index d4f312b8..6b82fd91 100644 --- a/packages/ui/scripts/size-limit.ts +++ b/packages/ui/scripts/size-limit.ts @@ -29,7 +29,7 @@ const ENTRIES: Entry[] = [ name: "./map", js: `export * from "./map/index.js";`, requires: "map/index.js", - external: ["maplibre-gl", "mapbox-gl", "@deck.gl/core", "@deck.gl/mapbox"], + external: ["maplibre-gl", "mapbox-gl", "@deck.gl/core", "@deck.gl/mapbox", "@deck.gl/maplibre"], }, { name: "./sound", diff --git a/packages/ui/src/lib/map/MapStage.svelte b/packages/ui/src/lib/map/MapStage.svelte index 2fd077e7..4f018897 100644 --- a/packages/ui/src/lib/map/MapStage.svelte +++ b/packages/ui/src/lib/map/MapStage.svelte @@ -18,7 +18,7 @@ accessToken?: string; /** Basemap style per color scheme. The map switches style when `colorScheme.resolved` changes, without being recreated. */ styles: MapStyles; - /** deck.gl layers drawn interleaved in the map. Needs `@deck.gl/core` and `@deck.gl/mapbox`. Replace the array to update. */ + /** deck.gl layers drawn interleaved in the map. Needs `@deck.gl/core` plus `@deck.gl/maplibre` (`engine="maplibre"`) or `@deck.gl/mapbox` (`engine="mapbox"`). Replace the array to update. */ layers?: unknown[]; /** Bounds to fit, with `padding`. Changing it fits again. */ fit?: MapBounds; @@ -137,7 +137,7 @@ return; } let cancelled = false; - loadDeckOverlay(current) + loadDeckOverlay(current, engine) .then((o) => { if (cancelled) return o.finalize(); overlay = o; diff --git a/packages/ui/src/lib/map/MapStage.test.svelte b/packages/ui/src/lib/map/MapStage.test.svelte index 7f697284..a9f87b52 100644 --- a/packages/ui/src/lib/map/MapStage.test.svelte +++ b/packages/ui/src/lib/map/MapStage.test.svelte @@ -2,7 +2,11 @@ // Harness: MapStage + MapControls with an offline style per scheme, exposing the map handle. import MapStage from './MapStage.svelte'; import MapControls from './MapControls.svelte'; - import type { Map as GlMap } from 'maplibre-gl'; + import { setWorkerUrl, type Map as GlMap } from 'maplibre-gl'; + // maplibre-gl 6 ships its worker as a separate module and cannot find it once a bundler moves the + // package: the app wires it once (`setWorkerUrl`), as every bundler recipe in its docs does. + import workerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url'; + setWorkerUrl(workerUrl); let { onready, ...rest }: { onready?: (m: GlMap) => void; [k: string]: unknown } = $props(); diff --git a/packages/ui/src/lib/map/index.ts b/packages/ui/src/lib/map/index.ts index 6399be50..aeabf346 100644 --- a/packages/ui/src/lib/map/index.ts +++ b/packages/ui/src/lib/map/index.ts @@ -1,5 +1,5 @@ // @codeatlasdev/ui/map: needs the optional peers `maplibre-gl` or `mapbox-gl`, and for deck.gl -// layers `@deck.gl/core` + `@deck.gl/mapbox`. +// layers `@deck.gl/core` + `@deck.gl/maplibre` (maplibre-gl) or `@deck.gl/mapbox` (mapbox-gl). export type { Rgba } from "./color.js"; export { rgbaCss, tokenColor } from "./color.js"; export { default as MapControls } from "./MapControls.svelte"; diff --git a/packages/ui/src/lib/map/loader.ts b/packages/ui/src/lib/map/loader.ts index ad4e8b2b..1dbf3171 100644 --- a/packages/ui/src/lib/map/loader.ts +++ b/packages/ui/src/lib/map/loader.ts @@ -28,21 +28,32 @@ export async function loadEngine(engine: "maplibre" | "mapbox"): Promise { +/** + * `@deck.gl/mapbox` `MapboxOverlay` reads `map.transform.height`, which maplibre-gl 6 removed, so it + * throws on every frame there (#470). `@deck.gl/maplibre` `MapLibreOverlay` is the overlay deck.gl + * supports for maplibre-gl 4.5.1, 5 and 6; `MapboxOverlay` stays for mapbox-gl. + */ +export async function loadDeckOverlay( + layers: unknown[], + engine: "maplibre" | "mapbox" = "maplibre" +): Promise { + const pkg = engine === "mapbox" ? "@deck.gl/mapbox" : "@deck.gl/maplibre"; try { - const { MapboxOverlay } = await import("@deck.gl/mapbox"); - return new MapboxOverlay({ - interleaved: true, - layers: layers as ConstructorParameters[0]["layers"], - }) as unknown as DeckOverlay; + const props = { interleaved: true, layers: layers as never }; + if (engine === "mapbox") { + const { MapboxOverlay } = await import("@deck.gl/mapbox"); + return new MapboxOverlay(props) as unknown as DeckOverlay; + } + const { MapLibreOverlay } = await import("@deck.gl/maplibre"); + return new MapLibreOverlay(props) as unknown as DeckOverlay; } catch (cause) { throw new Error( - '[ca-ui] needs the optional peers "@deck.gl/core" and "@deck.gl/mapbox" (same ~9.4 minor) with maplibre-gl 5: install them.', + `[ca-ui] needs the optional peers "@deck.gl/core" and "${pkg}" (same ~9.4 minor): install them.`, { cause } ); } diff --git a/packages/ui/vite.config.ts b/packages/ui/vite.config.ts index 46a828c6..0bd7973d 100644 --- a/packages/ui/vite.config.ts +++ b/packages/ui/vite.config.ts @@ -45,7 +45,9 @@ export default defineConfig({ plugins: [svelte()], server: { fs: { allow: [searchForWorkspaceRoot(process.cwd()), ...fontDirs] } }, // Pre-bundle lazily imported deps so the first browser run doesn't trigger an optimizer reload. - optimizeDeps: { include: ["echarts", "@tanstack/svelte-table", "shiki", "axe-core"] }, + optimizeDeps: { + include: ["echarts", "@tanstack/svelte-table", "shiki", "axe-core", "@deck.gl/maplibre"], + }, test: { expect: { requireAssertions: true }, // Locally: a quarter of the cores (each worker is a browser tab in one Chromium). CI keeps the default. diff --git a/site/package.json b/site/package.json index 5a97f0b5..b9945d90 100644 --- a/site/package.json +++ b/site/package.json @@ -26,6 +26,7 @@ "@deck.gl/core": "9.4.0", "@deck.gl/layers": "9.4.0", "@deck.gl/mapbox": "9.4.0", + "@deck.gl/maplibre": "9.4.0", "@fontsource-variable/inter": "5.3.0", "@fontsource-variable/jetbrains-mono": "5.3.0", "@lucide/svelte": "1.55.0", @@ -37,7 +38,7 @@ "echarts": "6.1.0", "gsap": "3.15.0", "lenis": "1.3.26", - "maplibre-gl": "5.24.0", + "maplibre-gl": "6.16.0", "marked": "18.1.1", "png-to-ico": "3.0.2", "shiki": "4.5.0", diff --git a/site/public/api/v1/en/e/800.txt b/site/public/api/v1/en/e/800.txt index 323b6030..632da1a3 100644 --- a/site/public/api/v1/en/e/800.txt +++ b/site/public/api/v1/en/e/800.txt @@ -15,8 +15,13 @@ Live demo: https://ui.codeatlas.com.br/docs/map/stage#themed-map