From b16fb73398622fff97c73248639c410b90964ccf Mon Sep 17 00:00:00 2001 From: Jovanni Lo Date: Fri, 11 Sep 2026 02:15:23 +0800 Subject: [PATCH 1/4] fix(example): reuse static map overlays in details --- docs/content/docs/usage.mdx | 2 ++ .../shared/src/screens/MarkerDetailScreen.tsx | 32 ++++++++++++++++--- .../shared/src/screens/StaticMapsScreen.tsx | 8 ++--- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/docs/content/docs/usage.mdx b/docs/content/docs/usage.mdx index dc25258..0a07d45 100644 --- a/docs/content/docs/usage.mdx +++ b/docs/content/docs/usage.mdx @@ -105,6 +105,8 @@ Mounting many live maps is expensive. Use `staticMode` to render lightweight, no ``` +The example app uses the same markers and polyline in each static list map and its detail screen. + Read more in [Static Maps](./components/map-view.mdx#static-maps). ## Next steps diff --git a/example/shared/src/screens/MarkerDetailScreen.tsx b/example/shared/src/screens/MarkerDetailScreen.tsx index aaf465f..ffc9b14 100644 --- a/example/shared/src/screens/MarkerDetailScreen.tsx +++ b/example/shared/src/screens/MarkerDetailScreen.tsx @@ -1,11 +1,17 @@ -import { StyleSheet, View } from 'react-native'; +import { Platform, StyleSheet, View, useWindowDimensions } from 'react-native'; import { MapProvider, MapView, Marker } from '@lugg/maps'; import { ThemedText } from '../components'; import { INITIAL_MARKERS } from '../markers'; import { CIRCLE_CENTER } from '../mapData'; import { sizes, useTheme } from '../theme'; -import { PLACES } from './StaticMapsScreen'; +import { + PLACES, + PlaceConstellation, + PlaceMarkers, + fittedCamera, + placeCoordinates, +} from './StaticMapsScreen'; interface MarkerDetailScreenProps { name: string; @@ -18,6 +24,7 @@ const formatCoordinate = (value: number) => value.toFixed(4); export const MarkerDetailScreen = ({ name }: MarkerDetailScreenProps) => { const { colors } = useTheme(); + const { width, height } = useWindowDimensions(); const apiKey = process.env.GOOGLE_MAPS_API_KEY; const marker = INITIAL_MARKERS.find((m) => m.name === name); @@ -27,6 +34,14 @@ export const MarkerDetailScreen = ({ name }: MarkerDetailScreenProps) => { const title = marker?.title ?? place?.name ?? name; const description = marker?.description ?? place?.description ?? 'Marker detail screen'; + const camera = place + ? fittedCamera( + placeCoordinates(place), + Platform.OS === 'ios' ? 'apple' : 'google', + { width, height: height - CARD_BOTTOM - CARD_HEIGHT }, + sizes.xl + ) + : { coordinate, zoom: 15 }; return ( @@ -35,8 +50,8 @@ export const MarkerDetailScreen = ({ name }: MarkerDetailScreenProps) => { style={StyleSheet.absoluteFill} staticMode staticKey={name} - initialCoordinate={coordinate} - initialZoom={15} + initialCoordinate={camera.coordinate} + initialZoom={camera.zoom} edgeInsets={{ top: 0, left: 0, @@ -44,7 +59,14 @@ export const MarkerDetailScreen = ({ name }: MarkerDetailScreenProps) => { bottom: CARD_BOTTOM + CARD_HEIGHT, }} > - + {place ? ( + <> + + + + ) : ( + + )} [ // Every coordinate rendered on a place's map (markers + constellation), // used to fit the camera around the content -const placeCoordinates = (place: StaticPlace): Coordinate[] => { +export const placeCoordinates = (place: StaticPlace): Coordinate[] => { const coordinates = [ place.coordinate, ...constellationPoints(place.coordinate, seedFromId(place.id)), @@ -162,7 +162,7 @@ const mercatorY = (latitude: number) => // Matches the native static framing: Google shows the world 256 * 2^zoom // points wide; Apple fits a square span rect to the view's short side // (see LuggStaticFittedMapRect) -const fittedCamera = ( +export const fittedCamera = ( coordinates: Coordinate[], provider: MapProviderType, size: { width: number; height: number }, @@ -202,7 +202,7 @@ const fittedCamera = ( return { coordinate, zoom }; }; -const PlaceConstellation = ({ place }: { place: StaticPlace }) => { +export const PlaceConstellation = ({ place }: { place: StaticPlace }) => { const points = constellationPoints(place.coordinate, seedFromId(place.id)); return ( <> @@ -220,7 +220,7 @@ const PlaceConstellation = ({ place }: { place: StaticPlace }) => { ); }; -const PlaceMarkers = ({ place }: { place: StaticPlace }) => { +export const PlaceMarkers = ({ place }: { place: StaticPlace }) => { const { coordinate, markerType, markerText, imageUrl } = place; switch (markerType) { From 2d7d8df103865f5cb96392eec4469c3dc4212d33 Mon Sep 17 00:00:00 2001 From: Jovanni Lo Date: Fri, 11 Sep 2026 02:15:47 +0800 Subject: [PATCH 2/4] feat(example): toggle static map provider in details --- docs/content/docs/usage.mdx | 1 + .../shared/src/screens/MarkerDetailScreen.tsx | 25 ++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/docs/content/docs/usage.mdx b/docs/content/docs/usage.mdx index 0a07d45..c70c8bc 100644 --- a/docs/content/docs/usage.mdx +++ b/docs/content/docs/usage.mdx @@ -106,6 +106,7 @@ Mounting many live maps is expensive. Use `staticMode` to render lightweight, no ``` The example app uses the same markers and polyline in each static list map and its detail screen. +On iOS, both screens include a button to switch between Apple Maps and Google Maps. Read more in [Static Maps](./components/map-view.mdx#static-maps). diff --git a/example/shared/src/screens/MarkerDetailScreen.tsx b/example/shared/src/screens/MarkerDetailScreen.tsx index ffc9b14..a7840d4 100644 --- a/example/shared/src/screens/MarkerDetailScreen.tsx +++ b/example/shared/src/screens/MarkerDetailScreen.tsx @@ -1,7 +1,8 @@ +import { useState } from 'react'; import { Platform, StyleSheet, View, useWindowDimensions } from 'react-native'; -import { MapProvider, MapView, Marker } from '@lugg/maps'; +import { MapProvider, MapView, Marker, type MapProviderType } from '@lugg/maps'; -import { ThemedText } from '../components'; +import { Button, ThemedText } from '../components'; import { INITIAL_MARKERS } from '../markers'; import { CIRCLE_CENTER } from '../mapData'; import { sizes, useTheme } from '../theme'; @@ -26,6 +27,9 @@ export const MarkerDetailScreen = ({ name }: MarkerDetailScreenProps) => { const { colors } = useTheme(); const { width, height } = useWindowDimensions(); const apiKey = process.env.GOOGLE_MAPS_API_KEY; + const [provider, setProvider] = useState( + Platform.OS === 'ios' ? 'apple' : 'google' + ); const marker = INITIAL_MARKERS.find((m) => m.name === name); const place = PLACES.find((p) => p.name === name); @@ -37,7 +41,7 @@ export const MarkerDetailScreen = ({ name }: MarkerDetailScreenProps) => { const camera = place ? fittedCamera( placeCoordinates(place), - Platform.OS === 'ios' ? 'apple' : 'google', + provider, { width, height: height - CARD_BOTTOM - CARD_HEIGHT }, sizes.xl ) @@ -47,6 +51,8 @@ export const MarkerDetailScreen = ({ name }: MarkerDetailScreenProps) => { { )} +