From 7e302b1fbeb80c5cfcc589039debdc9808e74d36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Sun, 19 Apr 2026 12:09:06 +0200 Subject: [PATCH] Upgrade @maplibre/maplibre-react-native from 10 to 11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v11 is a breaking API rework (renamed components, restructured props, event payloads on nativeEvent) and requires React Native's new architecture. Doing it as a manual migration instead of taking dependabot's #268 because the renames need code changes. Changes in apps/mobile: - RouteMap.tsx — switch to named imports; rename MapView→Map, ShapeSource→GeoJSONSource (with shape→data), LineLayer→Layer (with type="line" and paint instead of style), MarkerView→ ViewAnnotation (with coordinate→lngLat); Camera uses initialViewState with bounds as [w,s,e,n] and a separate padding object; onLongPress reads lngLat from event.nativeEvent. - app.config.ts — set `newArchEnabled: true`. MapLibre RN v11 supports only the new architecture, so Fabric/TurboModules must be on for the Expo prebuild. Cast the config type since Expo SDK 55's ExpoConfig typings don't yet include the field (the runtime does). - package.json — `^10.4.2` → `^11.0.0`. Supersedes dependabot #268; it'll auto-close once this merges. Runtime verification requires an EAS dev build (native deps changed + new arch flipped). JS-only surface typechecks + lints + unit tests clean locally. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/mobile/app.config.ts | 7 ++- apps/mobile/lib/editor/RouteMap.tsx | 76 ++++++++++++++++------------- apps/mobile/package.json | 2 +- pnpm-lock.yaml | 72 +++++++++++++++++++++------ 4 files changed, 104 insertions(+), 53 deletions(-) diff --git a/apps/mobile/app.config.ts b/apps/mobile/app.config.ts index 1cc21cd..7e0dc7b 100644 --- a/apps/mobile/app.config.ts +++ b/apps/mobile/app.config.ts @@ -1,11 +1,16 @@ import { ExpoConfig, ConfigContext } from "expo/config"; -export default ({ config }: ConfigContext): ExpoConfig => ({ +// `newArchEnabled` isn't in the Expo SDK 55 typings yet but is an +// accepted runtime flag. MapLibre RN v11 requires the new architecture. +type ExpoConfigWithNewArch = ExpoConfig & { newArchEnabled?: boolean }; + +export default ({ config }: ConfigContext): ExpoConfigWithNewArch => ({ ...config, name: "trails.cool", slug: "mobile", version: "0.0.1", scheme: "trailscool", + newArchEnabled: true, orientation: "portrait", icon: "./assets/icon.png", userInterfaceStyle: "light", diff --git a/apps/mobile/lib/editor/RouteMap.tsx b/apps/mobile/lib/editor/RouteMap.tsx index 49c177d..afcd600 100644 --- a/apps/mobile/lib/editor/RouteMap.tsx +++ b/apps/mobile/lib/editor/RouteMap.tsx @@ -1,6 +1,13 @@ import { useRef, useCallback } from "react"; import { StyleSheet, View, Text } from "react-native"; -import MapLibreGL from "@maplibre/maplibre-react-native"; +import { + Camera, + GeoJSONSource, + Layer, + Map, + ViewAnnotation, + type CameraRef, +} from "@maplibre/maplibre-react-native"; import type { Waypoint } from "@trails-cool/types"; import type { RouteSegment } from "./use-route-editor"; @@ -40,7 +47,10 @@ export function RouteMap({ onWaypointDragEnd: _onWaypointDragEnd, onWaypointPress, }: RouteMapProps) { - if (!MapLibreGL) { + // `Map` is undefined when the native module isn't linked (e.g. running + // in Expo Go). Same safety net as before the v11 upgrade, just against + // a named import instead of the removed default export. + if (!Map) { return ( Map @@ -64,15 +74,16 @@ function RouteMapInner({ onWaypointDragEnd: _onWaypointDragEnd, onWaypointPress, }: RouteMapProps) { - const ML = MapLibreGL!; - const cameraRef = useRef(null); + const cameraRef = useRef(null); const handleLongPress = useCallback( // eslint-disable-next-line @typescript-eslint/no-explicit-any (event: any) => { - const coords = event?.geometry?.coordinates; - if (Array.isArray(coords) && coords.length >= 2) { - onLongPress(coords[1] as number, coords[0] as number); + // v11 event shape: payload lives on `event.nativeEvent.lngLat` + // (the old `event.geometry.coordinates` is gone). + const lngLat = event?.nativeEvent?.lngLat; + if (Array.isArray(lngLat) && lngLat.length >= 2) { + onLongPress(lngLat[1] as number, lngLat[0] as number); } }, [onLongPress], @@ -96,64 +107,59 @@ function RouteMapInner({ return ( - {bounds && ( - )} {!bounds && ( - )} {/* Route line */} - - + - + {/* Waypoint markers */} {waypoints.map((wp, i) => ( - onWaypointPress(i)} /> - + ))} - + {computing && ( diff --git a/apps/mobile/package.json b/apps/mobile/package.json index 4bd2597..f9ec41a 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -31,7 +31,7 @@ "dependencies": { "@expo/metro-runtime": "^55.0.9", "@gorhom/bottom-sheet": "^5.2.9", - "@maplibre/maplibre-react-native": "^10.4.2", + "@maplibre/maplibre-react-native": "^11.0.0", "@sentry/cli": "^3.3.5", "@sentry/react-native": "~7.11.0", "@trails-cool/api": "workspace:*", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3cd855d..7362be2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -313,8 +313,8 @@ importers: specifier: ^5.2.9 version: 5.2.9(@types/react@19.2.14)(react-native-gesture-handler@2.31.1(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native-reanimated@4.3.0(react-native-worklets@0.8.1(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5))(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@maplibre/maplibre-react-native': - specifier: ^10.4.2 - version: 10.4.2(@expo/config-plugins@55.0.8)(@types/geojson@7946.0.16)(@types/react@19.2.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) + specifier: ^11.0.0 + version: 11.0.0(@expo/config-plugins@55.0.8)(@types/geojson@7946.0.16)(@types/react@19.2.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5) '@sentry/cli': specifier: ^3.3.5 version: 3.3.5 @@ -2099,14 +2099,25 @@ packages: '@lezer/lr@1.4.8': resolution: {integrity: sha512-bPWa0Pgx69ylNlMlPvBPryqeLYQjyJjqPx+Aupm5zydLIF3NE+6MMLT8Yi23Bd9cif9VS00aUebn+6fDIGBcDA==} - '@maplibre/maplibre-react-native@10.4.2': - resolution: {integrity: sha512-5qAfaEe66eMXyILklm2DMHwyaXwXxsZWVop4BqfU7AyTg13LHAcaMmLJNJ3jPkMtiJvjH2m8ywGnobdIg2I0lg==} + '@mapbox/jsonlint-lines-primitives@2.0.2': + resolution: {integrity: sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==} + engines: {node: '>= 0.6'} + + '@mapbox/unitbezier@0.0.1': + resolution: {integrity: sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==} + + '@maplibre/maplibre-gl-style-spec@24.8.1': + resolution: {integrity: sha512-zxa92qF96ZNojLxeAjnaRpjVCy+swoUNJvDhtpC90k7u5F0TMr4GmvNqMKvYrMoPB8d7gRSXbMG1hBbmgESIsw==} + hasBin: true + + '@maplibre/maplibre-react-native@11.0.0': + resolution: {integrity: sha512-OCds0j9+1kKkx0B5DikMpYvrzCwYv3ti5j9K0eQadq/M0RjQ40CFUdVpi4N0DtZXZxThmnMI5huqArN6G9GmHw==} peerDependencies: - '@expo/config-plugins': '>=7' + '@expo/config-plugins': '>=54.0.0' '@types/geojson': ^7946.0.0 - '@types/react': '>=16.6.1' + '@types/react': '>=19.1.0' react: ^19.2.5 - react-native: '>=0.59.9' + react-native: '>=0.80.0' peerDependenciesMeta: '@expo/config-plugins': optional: true @@ -3794,6 +3805,7 @@ packages: '@xmldom/xmldom@0.8.12': resolution: {integrity: sha512-9k/gHF6n/pAi/9tqr3m3aqkuiNosYTurLLUtc7xQ9sxB/wm7WPygCv8GYa6mS0fLJEHhqMC1ATYhz++U/lRHqg==} engines: {node: '>=10.0.0'} + deprecated: this version has critical issues, please update to the latest version abab@2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} @@ -4329,10 +4341,6 @@ packages: dateformat@4.6.3: resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} - debounce@2.2.0: - resolution: {integrity: sha512-Xks6RUDLZFdz8LIdR6q0MTH44k7FikOmnh5xkSjMig6ch45afc8sjTjRQf3P6ax8dMgcQrYO/AR2RGWURrruqw==} - engines: {node: '>=18'} - debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -5647,6 +5655,9 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json-stringify-pretty-compact@4.0.0: + resolution: {integrity: sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==} + json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -6511,6 +6522,9 @@ packages: quickselect@2.0.0: resolution: {integrity: sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==} + quickselect@3.0.0: + resolution: {integrity: sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==} + range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} @@ -6781,6 +6795,9 @@ packages: rtl-detect@1.1.2: resolution: {integrity: sha512-PGMBq03+TTG/p/cRB7HCLKJ1MgDIi07+QU1faSjiYRfmY5UsAttV9Hs08jDAHVwcOwmVLcSJkpwyfXszVjWfIQ==} + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} @@ -7110,6 +7127,9 @@ packages: tinyqueue@2.0.3: resolution: {integrity: sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==} + tinyqueue@3.0.0: + resolution: {integrity: sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==} + tinyrainbow@3.1.0: resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.0.0'} @@ -7728,7 +7748,7 @@ snapshots: '@babel/types': 7.29.0 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.0.2 + jsesc: 3.1.0 '@babel/helper-annotate-as-pure@7.27.3': dependencies: @@ -9278,13 +9298,27 @@ snapshots: dependencies: '@lezer/common': 1.5.2 - '@maplibre/maplibre-react-native@10.4.2(@expo/config-plugins@55.0.8)(@types/geojson@7946.0.16)(@types/react@19.2.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': + '@mapbox/jsonlint-lines-primitives@2.0.2': {} + + '@mapbox/unitbezier@0.0.1': {} + + '@maplibre/maplibre-gl-style-spec@24.8.1': dependencies: + '@mapbox/jsonlint-lines-primitives': 2.0.2 + '@mapbox/unitbezier': 0.0.1 + json-stringify-pretty-compact: 4.0.0 + minimist: 1.2.8 + quickselect: 3.0.0 + rw: 1.3.3 + tinyqueue: 3.0.0 + + '@maplibre/maplibre-react-native@11.0.0(@expo/config-plugins@55.0.8)(@types/geojson@7946.0.16)(@types/react@19.2.14)(react-native@0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5))(react@19.2.5)': + dependencies: + '@maplibre/maplibre-gl-style-spec': 24.8.1 '@turf/distance': 7.3.4 '@turf/helpers': 7.3.4 '@turf/length': 7.3.4 '@turf/nearest-point-on-line': 7.3.4 - debounce: 2.2.0 react: 19.2.5 react-native: 0.83.4(@babel/core@7.29.0)(@react-native/metro-config@0.85.1(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.5) optionalDependencies: @@ -11836,8 +11870,6 @@ snapshots: dateformat@4.6.3: {} - debounce@2.2.0: {} - debug@2.6.9: dependencies: ms: 2.0.0 @@ -13441,6 +13473,8 @@ snapshots: json-stable-stringify-without-jsonify@1.0.1: {} + json-stringify-pretty-compact@4.0.0: {} + json5@2.2.3: {} keyv@4.5.4: @@ -14584,6 +14618,8 @@ snapshots: quickselect@2.0.0: {} + quickselect@3.0.0: {} + range-parser@1.2.1: {} raw-body@2.5.3: @@ -14927,6 +14963,8 @@ snapshots: rtl-detect@1.1.2: {} + rw@1.3.3: {} + safe-buffer@5.1.2: {} safe-buffer@5.2.1: {} @@ -15231,6 +15269,8 @@ snapshots: tinyqueue@2.0.3: {} + tinyqueue@3.0.0: {} + tinyrainbow@3.1.0: {} tldts-core@7.0.28: {}