diff --git a/README.md b/README.md
index 706bd8a..7c67466 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,11 @@
# react-native-google-maps-plus
[](https://www.npmjs.com/package/react-native-google-maps-plus)
-[](https://www.npmjs.com/package/react-native-google-maps-plus)
-[](https://github.com/pinpong/react-native-google-maps-plus/actions/workflows/release.yml)
-[](https://github.com/pinpong/react-native-google-maps-plus/issues)
-[](./LICENSE)
-[](https://prettier.io/)
-[](https://www.typescriptlang.org/)
-[](https://eslint.org/)
-[](https://reactnative.dev/)
-[](https://developer.android.com/)
-[](https://developer.apple.com/ios/)
+[](https://www.npmjs.com/package/react-native-google-maps-plus)
+[](https://github.com/pinpong/react-native-google-maps-plus/actions/workflows/release.yml)
+
+
+
React Native wrapper for Android & iOS Google Maps SDK.
@@ -22,6 +17,58 @@ React Native wrapper for Android & iOS Google Maps SDK.
yarn add react-native-google-maps-plus react-native-nitro-modules
```
+**iOS**
+
+Add this to your Podfile only for bare React Native apps.
+(Not required for Expo, handled by the config plugin.)
+
+```ruby
+post_install do |installer|
+ react_native_post_install(
+ installer,
+ config[:reactNativePath],
+ :mac_catalyst_enabled => false,
+ )
+ # Force iOS 16+ to avoid deployment target warnings
+ installer.pods_project.targets.each do |target|
+ target.build_configurations.each do |config|
+ config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '16.0'
+ end
+ end
+
+ # --- SVGKit Patch ---
+ require 'fileutils'
+ svgkit_path = File.join(installer.sandbox.pod_dir('SVGKit'), 'Source')
+
+ # node fix
+ Dir.glob(File.join(svgkit_path, '**', '*.{h,m}')).each do |file|
+ FileUtils.chmod("u+w", file)
+ text = File.read(file)
+ new_contents = text.gsub('#import "Node.h"', '#import "SVGKit/Node.h"')
+ File.open(file, 'w') { |f| f.write(new_contents) }
+ # puts "Patched Node import in: #{file}"
+ end
+
+ # import CSSValue.h
+ Dir.glob(File.join(svgkit_path, '**', '*.{h,m}')).each do |file|
+ FileUtils.chmod("u+w", file)
+ text = File.read(file)
+ new_contents = text.gsub('#import "CSSValue.h"', '#import "SVGKit/CSSValue.h"')
+ File.open(file, 'w') { |f| f.write(new_contents) }
+ # puts "Patched CSSValue import in: #{file}"
+ end
+
+ # import SVGLength.h
+ Dir.glob(File.join(svgkit_path, '**', '*.{h,m}')).each do |file|
+ FileUtils.chmod("u+w", file)
+ text = File.read(file)
+ new_contents = text.gsub('#import "SVGLength.h"', '#import "SVGKit/SVGLength.h"')
+ File.open(file, 'w') { |f| f.write(new_contents) }
+ # puts "Patched SVGLength import in: #{file}"
+ end
+end
+```
+
### Expo Projects
Add your keys to the `app.json`.
@@ -43,148 +90,79 @@ The config plugin automatically injects them into your native Android and iOS bu
}
```
-# Dependencies
-
-This package builds on native libraries for SVG rendering and Google Maps integration:
-
-- **iOS**: [SVGKit](https://github.com/SVGKit/SVGKit)
-- **Android**: [AndroidSVG](https://bigbadaboom.github.io/androidsvg/)
-- **iOS Maps SDK**: [Google Maps SDK for iOS](https://developers.google.com/maps/documentation/ios-sdk)
-- **Android Maps SDK**: [Google Maps SDK for Android](https://developers.google.com/maps/documentation/android-sdk)
-- **Maps Utility Libraries**: [Google Maps Utils for iOS](https://developers.google.com/maps/documentation/ios-sdk/utility) and [Google Maps Utils for Android](https://developers.google.com/maps/documentation/android-sdk/utility)
-
-These are automatically linked when you install the package, but you may need to clean/rebuild your native projects after first install.
-
## Setup API Key
You will need a valid **Google Maps API Key** from the [Google Cloud Console](https://console.cloud.google.com/).
### Android
-It's recommend to use [Secrets Gradle Plugin](https://developers.google.com/maps/documentation/android-sdk/secrets-gradle-plugin) to securely manage your Google Maps API Key.
+**Note:** These instructions apply to **bare React Native apps only**.
+Expo projects should use the config plugin instead (see Expo section above).
----
+See the official [Google Maps Android SDK configuration guide](https://developers.google.com/maps/documentation/android-sdk/config#step_3_add_your_api_key_to_the_project) for more details.
### iOS
-See the official [Google Maps iOS SDK configuration guide](https://developers.google.com/maps/documentation/ios-sdk/config#get-key) for more details.
+**Note:** These instructions apply to **bare React Native apps only**.
+Expo projects should use the config plugin instead (see Expo section above).
-1. Create a `Secrets.xcconfig` file inside the **ios/** folder:
+See the official [Google Maps iOS SDK configuration guide](https://developers.google.com/maps/documentation/ios-sdk/config#get-key) for more details.
- ```properties
- MAPS_API_KEY=YOUR_IOS_MAPS_API_KEY
- ```
+## Dependencies & Native Documentation
- Include it in your project configuration file:
+This package is React Native wrapper around the official Google Maps SDKs.
+For full API behavior, configuration options, and feature reference, please consult the native documentation:
- ```xcconfig
- #include? "Secrets.xcconfig"
- ```
+- **iOS Google Maps SDK**
+ https://developers.google.com/maps/documentation/ios-sdk
-2. Reference the API key in your **Info.plist**:
+- **Android Google Maps SDK**
+ https://developers.google.com/maps/documentation/android-sdk
- ```xml
- MAPS_API_KEY
- $(MAPS_API_KEY)
- ```
+- **Maps Utility Libraries (iOS & Android)**
+ https://developers.google.com/maps/documentation/ios-sdk/utility
+ https://developers.google.com/maps/documentation/android-sdk/utility
-3. Provide the key programmatically in **AppDelegate.swift**:
+- **SVG Rendering** (used for custom marker icons)
+ - iOS: https://github.com/SVGKit/SVGKit
+ - Android: https://bigbadaboom.github.io/androidsvg/
- ```swift
- import GoogleMaps
+These libraries are automatically linked during installation.
+If you encounter build issues, try cleaning and rebuilding your native project.
- @UIApplicationMain
- class AppDelegate: UIResponder, UIApplicationDelegate {
- func application(_ application: UIApplication,
- didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
- if let apiKey = Bundle.main.object(forInfoDictionaryKey: "MAPS_API_KEY") as? String {
- GMSServices.provideAPIKey(apiKey)
- }
- return true
- }
- }
- ```
-
----
+> **Note:** This package follows the native SDKs closely. Props and behavior match the underlying Google Maps APIs whenever possible.
## Usage
-Checkout the example app in the [example](./example) folder.
-
-# Troubleshooting
-
-## Android
-
-- **API key not found**
- Make sure `secrets.properties` exists under `android/` and contains your `MAPS_API_KEY`.
- Run `./gradlew clean` and rebuild.
-
-## iOS
-
-- **`GMSServices must be configured before use`**
- Ensure your key is in `Info.plist` and/or provided via `GMSServices.provideAPIKey(...)` in `AppDelegate.swift`.
-
-- **Build fails with `Node.h`, `CSSValue.h`, or `SVGLength.h` import errors from SVGKit**
- SVGKit includes headers (`Node.h`, `CSSValue.h`, `SVGLength.h`) that can conflict with
- iOS system headers and React Native Reanimated’s internal types.
- You can patch them automatically in your **Podfile** inside the `post_install`
-
- ```ruby
- post_install do |installer|
- react_native_post_install(
- installer,
- config[:reactNativePath],
- :mac_catalyst_enabled => false,
- )
- # Force iOS 16+ to avoid deployment target warnings
- installer.pods_project.targets.each do |target|
- target.build_configurations.each do |config|
- config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '16.0'
- end
- end
-
- # --- SVGKit Patch ---
- require 'fileutils'
- svgkit_path = File.join(installer.sandbox.pod_dir('SVGKit'), 'Source')
-
- # node fix
- Dir.glob(File.join(svgkit_path, '**', '*.{h,m}')).each do |file|
- FileUtils.chmod("u+w", file)
- text = File.read(file)
- new_contents = text.gsub('#import "Node.h"', '#import "SVGKit/Node.h"')
- File.open(file, 'w') { |f| f.write(new_contents) }
- # puts "Patched Node import in: #{file}"
- end
-
- # import CSSValue.h
- Dir.glob(File.join(svgkit_path, '**', '*.{h,m}')).each do |file|
- FileUtils.chmod("u+w", file)
- text = File.read(file)
- new_contents = text.gsub('#import "CSSValue.h"', '#import "SVGKit/CSSValue.h"')
- File.open(file, 'w') { |f| f.write(new_contents) }
- # puts "Patched CSSValue import in: #{file}"
- end
-
- # import SVGLength.h
- Dir.glob(File.join(svgkit_path, '**', '*.{h,m}')).each do |file|
- FileUtils.chmod("u+w", file)
- text = File.read(file)
- new_contents = text.gsub('#import "SVGLength.h"', '#import "SVGKit/SVGLength.h"')
- File.open(file, 'w') { |f| f.write(new_contents) }
- # puts "Patched SVGLength import in: #{file}"
- end
- end
- ```
-
- After applying this, run:
-
- ```sh
- cd ios && pod install --repo-update
- ```
+Basic map:
+
+```tsx
+import React from 'react';
+import { GoogleMapsView } from 'react-native-google-maps-plus';
+
+export default function App() {
+ return (
+
+ );
+}
+```
-- **Maps not rendering**
- - Check that your API key has **Maps SDK for Android/iOS** enabled in Google Cloud Console.
- - Make sure the key is not restricted to wrong bundle IDs or SHA1 fingerprints.
+Check out the example app in the [example](./example) folder.
## Contributing
diff --git a/android/src/main/java/com/rngooglemapsplus/extensions/RNUserInterfaceExtension.kt b/android/src/main/java/com/rngooglemapsplus/extensions/RNUserInterfaceExtension.kt
index 8fd4c5a..7e143b2 100644
--- a/android/src/main/java/com/rngooglemapsplus/extensions/RNUserInterfaceExtension.kt
+++ b/android/src/main/java/com/rngooglemapsplus/extensions/RNUserInterfaceExtension.kt
@@ -7,6 +7,6 @@ fun RNUserInterfaceStyle?.toMapColorScheme(): Int? =
when (this) {
RNUserInterfaceStyle.LIGHT -> MapColorScheme.LIGHT
RNUserInterfaceStyle.DARK -> MapColorScheme.DARK
- RNUserInterfaceStyle.DEFAULT -> MapColorScheme.FOLLOW_SYSTEM
+ RNUserInterfaceStyle.SYSTEM -> MapColorScheme.FOLLOW_SYSTEM
null -> null
}
diff --git a/example/src/components/ControlPanel.tsx b/example/src/components/ControlPanel.tsx
index 4dc96b3..60c6f1a 100644
--- a/example/src/components/ControlPanel.tsx
+++ b/example/src/components/ControlPanel.tsx
@@ -17,6 +17,11 @@ import type { GoogleMapsViewRef } from 'react-native-google-maps-plus';
import { useAppTheme } from '../hooks/useAppTheme';
import { useNavigation } from '@react-navigation/native';
import type { RootNavigationProp } from '../types/navigation';
+import {
+ type EdgeInsets,
+ useSafeAreaInsets,
+} from 'react-native-safe-area-context';
+import type { AppTheme } from '../theme';
export type ButtonItem = { title: string; onPress: () => void };
@@ -29,7 +34,8 @@ export default function ControlPanel({ mapRef, buttons }: Props) {
const theme = useAppTheme();
const navigation = useNavigation();
const progress = useSharedValue(0);
- const styles = useMemo(() => getThemedStyles(theme), [theme]);
+ const layout = useSafeAreaInsets();
+ const styles = useMemo(() => getThemedStyles(theme, layout), [layout, theme]);
const toggle = () => {
progress.value = withTiming(progress.value === 1 ? 0 : 1, {
@@ -124,7 +130,7 @@ export default function ControlPanel({ mapRef, buttons }: Props) {
);
}
-const getThemedStyles = (theme: any) =>
+const getThemedStyles = (theme: AppTheme, layout: EdgeInsets) =>
StyleSheet.create({
scrollView: {
position: 'absolute',
@@ -136,7 +142,7 @@ const getThemedStyles = (theme: any) =>
backgroundColor: theme.bgPrimary,
},
scrollContent: {
- paddingBottom: 40,
+ paddingBottom: layout.bottom + 8,
},
header: {
borderRadius: 10,
diff --git a/example/src/components/HeaderButton.tsx b/example/src/components/HeaderButton.tsx
index 2b988c2..69ca230 100644
--- a/example/src/components/HeaderButton.tsx
+++ b/example/src/components/HeaderButton.tsx
@@ -1,6 +1,7 @@
import React, { useMemo } from 'react';
import { Pressable, StyleSheet, Text } from 'react-native';
import { useAppTheme } from '../hooks/useAppTheme';
+import type { AppTheme } from '../theme';
type Props = {
title: string;
@@ -18,7 +19,7 @@ export default function HeaderButton({ title, onPress }: Props) {
);
}
-const getThemedStyles = (theme: any) =>
+const getThemedStyles = (theme: AppTheme) =>
StyleSheet.create({
headerButton: {
paddingHorizontal: 12,
diff --git a/example/src/components/MapWrapper.tsx b/example/src/components/MapWrapper.tsx
index 81415ce..b0fa0d3 100644
--- a/example/src/components/MapWrapper.tsx
+++ b/example/src/components/MapWrapper.tsx
@@ -25,7 +25,8 @@ import {
} from 'react-native-google-maps-plus';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { callback } from 'react-native-nitro-modules';
-import { useTheme } from '@react-navigation/native';
+import type { AppTheme } from '../theme';
+import { useAppTheme } from '../hooks/useAppTheme';
type Props = ViewProps &
RNGoogleMapsPlusViewProps & {
@@ -47,7 +48,7 @@ function wrapCallback void>(
export default function MapWrapper(props: Props) {
const { children, ...rest } = props;
- const theme = useTheme();
+ const theme = useAppTheme();
const styles = useMemo(() => getThemedStyles(theme), [theme]);
const layout = useSafeAreaInsets();
@@ -119,7 +120,8 @@ export default function MapWrapper(props: Props) {
indoorEnabled={props.indoorEnabled ?? false}
style={[styles.map, props.style]}
userInterfaceStyle={
- props.userInterfaceStyle ?? (theme.dark ? 'dark' : 'light')
+ props.userInterfaceStyle ??
+ (theme.theme === 'dark' ? 'dark' : 'light')
}
mapType={props.mapType ?? 'normal'}
mapZoomConfig={props.mapZoomConfig ?? mapZoomConfig}
@@ -231,18 +233,18 @@ export default function MapWrapper(props: Props) {
{children}
{!mapLoaded && (
-
+
)}
);
}
-const getThemedStyles = (theme: any) =>
+const getThemedStyles = (theme: AppTheme) =>
StyleSheet.create({
container: {
flex: 1,
- backgroundColor: theme.background,
+ backgroundColor: theme.bgPrimary,
},
map: {
position: 'absolute',
diff --git a/example/src/components/maptConfigDialog/MapConfigDialog.tsx b/example/src/components/maptConfigDialog/MapConfigDialog.tsx
index a348214..39bd26a 100644
--- a/example/src/components/maptConfigDialog/MapConfigDialog.tsx
+++ b/example/src/components/maptConfigDialog/MapConfigDialog.tsx
@@ -17,6 +17,7 @@ import {
parseWithUndefined,
stringifyWithUndefined,
} from './utils';
+import type { AppTheme } from '../../theme';
type Props = {
visible: boolean;
@@ -152,7 +153,7 @@ export default function MapConfigDialog({
);
}
-const getThemedStyles = (theme: any) =>
+const getThemedStyles = (theme: AppTheme) =>
StyleSheet.create({
overlay: {
flex: 1,
@@ -176,9 +177,10 @@ const getThemedStyles = (theme: any) =>
alignItems: 'center',
paddingHorizontal: 16,
paddingVertical: 12,
+ borderRadius: 16,
borderBottomWidth: StyleSheet.hairlineWidth,
borderColor: theme.border,
- backgroundColor: theme.bgSecondary,
+ backgroundColor: theme.bgPrimary,
},
headerActions: { flexDirection: 'row', gap: 8 },
headerButtonText: {
diff --git a/example/src/components/maptConfigDialog/validator.ts b/example/src/components/maptConfigDialog/validator.ts
index 80c6b91..e13e473 100644
--- a/example/src/components/maptConfigDialog/validator.ts
+++ b/example/src/components/maptConfigDialog/validator.ts
@@ -97,7 +97,7 @@ export const RNMapTypeValidator = unionWithValues(
export const RNUserInterfaceStyleValidator = unionWithValues(
'light',
'dark',
- 'default'
+ 'system'
);
export const RNPositionValidator = object({
diff --git a/example/src/screens/BasicMapScreen.tsx b/example/src/screens/BasicMapScreen.tsx
index 85bc51a..042b6b1 100644
--- a/example/src/screens/BasicMapScreen.tsx
+++ b/example/src/screens/BasicMapScreen.tsx
@@ -45,8 +45,7 @@ export default function BasicMapScreen() {
buildingEnabled: undefined,
trafficEnabled: undefined,
indoorEnabled: undefined,
- customMapStyle: '',
- userInterfaceStyle: 'default',
+ customMapStyle: undefined,
mapZoomConfig: { min: 0, max: 20 },
mapPadding: { top: 20, left: 20, bottom: layout.bottom + 80, right: 20 },
mapType: 'normal',
diff --git a/example/src/screens/BlankScreen.tsx b/example/src/screens/BlankScreen.tsx
index 8bf6cd2..51e557c 100644
--- a/example/src/screens/BlankScreen.tsx
+++ b/example/src/screens/BlankScreen.tsx
@@ -1,57 +1,62 @@
-import React from 'react';
+import React, { useMemo } from 'react';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
-import { useNavigation, useTheme } from '@react-navigation/native';
+import { useNavigation } from '@react-navigation/native';
import type { RootNavigationProp } from '../types/navigation';
+import { useAppTheme } from '../hooks/useAppTheme';
+import type { AppTheme } from '../theme';
export default function BlankScreen() {
const navigation = useNavigation();
- const { colors } = useTheme();
+ const theme = useAppTheme();
+ const styles = useMemo(() => getThemedStyles(theme), [theme]);
return (
-
- Blank Screen
+
+ Blank Screen
-
- This is an empty placeholder screen.
-
+ This is an empty placeholder screen.
navigation.goBack()}
>
-
- ← Go Back
-
+ Go Back
);
}
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- justifyContent: 'center',
- alignItems: 'center',
- padding: 24,
- },
- title: {
- fontSize: 24,
- fontWeight: '700',
- marginBottom: 8,
- },
- subtitle: {
- fontSize: 16,
- opacity: 0.8,
- marginBottom: 32,
- },
- button: {
- paddingHorizontal: 24,
- paddingVertical: 12,
- borderRadius: 10,
- },
- buttonText: {
- fontSize: 16,
- fontWeight: '500',
- },
-});
+const getThemedStyles = (theme: AppTheme) =>
+ StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ padding: 24,
+ backgroundColor: theme.bgPrimary,
+ },
+ title: {
+ color: theme.textPrimary,
+ fontSize: 24,
+ fontWeight: '700',
+ marginBottom: 8,
+ },
+ subtitle: {
+ color: theme.textPrimary,
+ fontSize: 16,
+ opacity: 0.8,
+ marginBottom: 32,
+ },
+ button: {
+ color: theme.buttonBg,
+ paddingHorizontal: 24,
+ paddingVertical: 12,
+ borderRadius: 10,
+ },
+ buttonText: {
+ color: theme.textPrimary,
+ fontSize: 16,
+ fontWeight: '500',
+ },
+ });
diff --git a/example/src/screens/HomeScreen.tsx b/example/src/screens/HomeScreen.tsx
index 580ed4a..47dc544 100644
--- a/example/src/screens/HomeScreen.tsx
+++ b/example/src/screens/HomeScreen.tsx
@@ -1,8 +1,16 @@
import React, { useMemo } from 'react';
import { ScrollView, StyleSheet, Text, TouchableOpacity } from 'react-native';
-import type { StackNavigationProp } from '@react-navigation/stack';
import { useNavigation } from '@react-navigation/native';
import { useAppTheme } from '../hooks/useAppTheme';
+import type { AppTheme } from '../theme';
+import type {
+ RootNavigationProp,
+ RootStackParamList,
+} from '../types/navigation';
+import {
+ type EdgeInsets,
+ useSafeAreaInsets,
+} from 'react-native-safe-area-context';
const screens = [
{ name: 'BasicMap', title: 'Basic Map' },
@@ -24,9 +32,10 @@ const screens = [
];
export default function HomeScreen() {
- const navigation = useNavigation>();
+ const navigation = useNavigation();
const theme = useAppTheme();
- const styles = useMemo(() => getThemedStyles(theme), [theme]);
+ const layout = useSafeAreaInsets();
+ const styles = useMemo(() => getThemedStyles(theme, layout), [theme, layout]);
return (
@@ -35,7 +44,9 @@ export default function HomeScreen() {
navigation.navigate(s.name)}
+ onPress={() =>
+ navigation.navigate(s.name as keyof RootStackParamList)
+ }
activeOpacity={0.85}
>
{s.title}
@@ -45,13 +56,13 @@ export default function HomeScreen() {
);
}
-const getThemedStyles = (theme: any) =>
+const getThemedStyles = (theme: AppTheme, layout: EdgeInsets) =>
StyleSheet.create({
container: {
flexGrow: 1,
alignItems: 'center',
justifyContent: 'center',
- paddingVertical: 40,
+ paddingVertical: layout.bottom + 8,
backgroundColor: theme.bgPrimary,
},
title: {
diff --git a/example/src/screens/MarkersScreen.tsx b/example/src/screens/MarkersScreen.tsx
index f308f83..1668342 100644
--- a/example/src/screens/MarkersScreen.tsx
+++ b/example/src/screens/MarkersScreen.tsx
@@ -3,6 +3,7 @@ import MapWrapper from '../components/MapWrapper';
import { makeMarker } from '../utils/mapGenerators';
import type {
GoogleMapsViewRef,
+ RNLatLng,
RNMarker,
} from 'react-native-google-maps-plus';
import MapConfigDialog from '../components/maptConfigDialog/MapConfigDialog';
@@ -10,13 +11,44 @@ import { useNavigation } from '@react-navigation/native';
import { RNMarkerValidator } from '../components/maptConfigDialog/validator';
import { useHeaderButton } from '../hooks/useHeaderButton';
import type { RNMapUiSettings } from 'react-native-google-maps-plus';
+import ControlPanel from '../components/ControlPanel';
+
+export function animateSpiral(
+ center: RNLatLng,
+ duration: number,
+ onUpdate: (c: RNLatLng) => void,
+ onFinish: () => void,
+ opts = { rotations: 10, startRadius: 0.0001, endRadius: 0.002 }
+) {
+ const { rotations, startRadius, endRadius } = opts;
+ const start = performance.now();
+
+ const ease = (t: number) => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t);
+
+ const loop = (now: number) => {
+ const t = Math.min((now - start) / duration, 1);
+ const e = ease(t);
+
+ const r = startRadius + (endRadius - startRadius) * e;
+ const angle = e * rotations * 2 * Math.PI;
+
+ onUpdate({
+ latitude: center.latitude + Math.cos(angle) * r,
+ longitude: center.longitude + Math.sin(angle) * r,
+ });
+
+ t < 1 ? requestAnimationFrame(loop) : onFinish();
+ };
+
+ requestAnimationFrame(loop);
+}
export default function MarkersScreen() {
const mapRef = useRef(null);
const navigation = useNavigation();
const [markers, setMarkers] = useState(undefined);
const [dialogVisible, setDialogVisible] = useState(true);
-
+ const animatingRef = useRef(false);
const uiSettings: RNMapUiSettings = useMemo(
() => ({
allGesturesEnabled: true,
@@ -40,6 +72,32 @@ export default function MarkersScreen() {
setDialogVisible(true)
);
+ const buttons = useMemo(
+ () => [
+ {
+ title: 'Animate Marker',
+ onPress: () => {
+ if (animatingRef.current) return;
+ if (!markers || !markers[0]) return;
+ const center = markers[0].coordinate;
+ const id = markers[0].id;
+ animatingRef.current = true;
+ animateSpiral(
+ center,
+ 5000,
+ (coordinate: RNLatLng) => {
+ setMarkers((prev) =>
+ prev?.map((m) => (m.id === id ? { ...m, coordinate } : m))
+ );
+ },
+ () => (animatingRef.current = false)
+ );
+ },
+ },
+ ],
+ [markers]
+ );
+
return (
<>
mapRef.current?.showMarkerInfoWindow(id)}
- />
+ >
+
+
visible={dialogVisible}
title="Edit marker"
diff --git a/example/src/screens/SnaptshotTestScreen.tsx b/example/src/screens/SnaptshotTestScreen.tsx
index 4e760b8..7468c27 100644
--- a/example/src/screens/SnaptshotTestScreen.tsx
+++ b/example/src/screens/SnaptshotTestScreen.tsx
@@ -4,6 +4,7 @@ import MapWrapper from '../components/MapWrapper';
import ControlPanel from '../components/ControlPanel';
import { useAppTheme } from '../hooks/useAppTheme';
import type { GoogleMapsViewRef } from 'react-native-google-maps-plus';
+import type { AppTheme } from '../theme';
export default function SnapshotTestScreen() {
const mapRef = useRef(null);
@@ -90,7 +91,7 @@ export default function SnapshotTestScreen() {
);
}
-const getThemedStyles = (theme: any) =>
+const getThemedStyles = (theme: AppTheme) =>
StyleSheet.create({
backdrop: {
flex: 1,
@@ -125,7 +126,7 @@ const getThemedStyles = (theme: any) =>
backgroundColor: theme.bgHeader,
},
noImage: {
- color: theme.textSecondary,
+ color: theme.textOnAccent,
marginBottom: 20,
},
closeButton: {
diff --git a/example/src/theme.ts b/example/src/theme.ts
index 824183a..4f0943b 100644
--- a/example/src/theme.ts
+++ b/example/src/theme.ts
@@ -1,4 +1,5 @@
export const lightTheme = {
+ theme: 'light',
bgPrimary: '#FFFFFF',
bgAccent: '#3B82F6',
bgHeader: '#E5E7EB',
@@ -16,6 +17,7 @@ export const lightTheme = {
};
export const darkTheme = {
+ theme: 'dark',
bgPrimary: '#1E1E1E',
bgAccent: '#2D6BE9',
bgHeader: '#2C2C2E',
diff --git a/example/src/types/navigation.ts b/example/src/types/navigation.ts
index c3ace83..5778d54 100644
--- a/example/src/types/navigation.ts
+++ b/example/src/types/navigation.ts
@@ -1,3 +1,5 @@
+import type { StackNavigationProp } from '@react-navigation/stack';
+
export type RootStackParamList = {
Home: undefined;
Blank: undefined;
@@ -19,6 +21,4 @@ export type RootStackParamList = {
Stress: undefined;
};
-import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
-
-export type RootNavigationProp = NativeStackNavigationProp;
+export type RootNavigationProp = StackNavigationProp;
diff --git a/ios/extensions/RNUserInterface+Extension.swift b/ios/extensions/RNUserInterface+Extension.swift
index 4ff0571..39ea6bc 100644
--- a/ios/extensions/RNUserInterface+Extension.swift
+++ b/ios/extensions/RNUserInterface+Extension.swift
@@ -7,7 +7,7 @@ extension RNUserInterfaceStyle {
return .light
case .dark:
return .dark
- case .default:
+ case .system:
return .unspecified
@unknown default:
return .unspecified
diff --git a/package.json b/package.json
index 1aeca69..b882365 100644
--- a/package.json
+++ b/package.json
@@ -101,12 +101,12 @@
"eslint-plugin-prettier": "5.5.4",
"jest": "30.2.0",
"lefthook": "2.0.2",
- "nitrogen": "0.30.2",
+ "nitrogen": "0.31.4",
"prettier": "3.6.2",
"react": "19.1.1",
"react-native": "0.82.1",
"react-native-builder-bob": "0.40.14",
- "react-native-nitro-modules": "0.30.2",
+ "react-native-nitro-modules": "0.31.4",
"semantic-release": "25.0.1",
"typescript": "5.9.3"
},
diff --git a/src/types.ts b/src/types.ts
index 354c8da..bc9a857 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -61,7 +61,7 @@ export type RNMapPadding = {
export type RNMapType = 'none' | 'normal' | 'hybrid' | 'satellite' | 'terrain';
-export type RNUserInterfaceStyle = 'light' | 'dark' | 'default';
+export type RNUserInterfaceStyle = 'light' | 'dark' | 'system';
export type RNFeatureType = string;
diff --git a/yarn.lock b/yarn.lock
index 10961e1..2154515 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2755,17 +2755,17 @@ __metadata:
linkType: hard
"@npmcli/package-json@npm:^7.0.0, @npmcli/package-json@npm:^7.0.1":
- version: 7.0.1
- resolution: "@npmcli/package-json@npm:7.0.1"
+ version: 7.0.2
+ resolution: "@npmcli/package-json@npm:7.0.2"
dependencies:
"@npmcli/git": ^7.0.0
glob: ^11.0.3
hosted-git-info: ^9.0.0
- json-parse-even-better-errors: ^4.0.0
- proc-log: ^5.0.0
+ json-parse-even-better-errors: ^5.0.0
+ proc-log: ^6.0.0
semver: ^7.5.3
validate-npm-package-license: ^3.0.4
- checksum: 8d6415999c80c744b1d59cdd03e9c9a3e7efe1ec744923d65e0f0cc5f72dc20fa87ad9dab95574b10d2d54b6b1d0846b9b7fd94812ecd32a5fed52eda65eaae9
+ checksum: cb237240c0f844f8e4b0fb13fb425c1abbfdc510e894412cdf88071c3bfb1bd864867797bd13d214a396ae51cc4f6d68a31eb23f9682f6898a7eb09d6e5be58b
languageName: node
linkType: hard
@@ -6084,9 +6084,9 @@ __metadata:
linkType: hard
"electron-to-chromium@npm:^1.5.238":
- version: 1.5.244
- resolution: "electron-to-chromium@npm:1.5.244"
- checksum: 0ca55077fa97c6a59e571d066bb1483399522d849758d878dd8e6b5ed0324c973da2448beb6cf630c2d700853824a633742158194d1345e6d2a53fa278dc8937
+ version: 1.5.245
+ resolution: "electron-to-chromium@npm:1.5.245"
+ checksum: 6262655d0dec8663df58056559a8f1f47648657debf0c868e49d8e3b5f866318c4a9105261272a5aaa529fc6140f4401e0e2c5fadbd24ed50cf9b5cd7e961bfc
languageName: node
linkType: hard
@@ -10541,18 +10541,18 @@ __metadata:
languageName: node
linkType: hard
-"nitrogen@npm:0.30.2":
- version: 0.30.2
- resolution: "nitrogen@npm:0.30.2"
+"nitrogen@npm:0.31.4":
+ version: 0.31.4
+ resolution: "nitrogen@npm:0.31.4"
dependencies:
chalk: ^5.3.0
- react-native-nitro-modules: ^0.30.2
+ react-native-nitro-modules: ^0.31.4
ts-morph: ^27.0.0
yargs: ^18.0.0
zod: ^4.0.5
bin:
nitrogen: lib/index.js
- checksum: b8692111891d70715b200d1c7adf129fe302cc8d85055ccb60144269970460b747d78caa110eadaee5c10f3cc077da46d53edbbc63ee9a5112a396e3256a2b32
+ checksum: 566abe01767d03860834b7b95093f1de5d7d7e010a556508e727afafc7476765d146452047adeee3aeaa5b0d361c504762695d8d3d6386e77f0091ff53e00d9c
languageName: node
linkType: hard
@@ -11955,12 +11955,12 @@ __metadata:
eslint-plugin-prettier: 5.5.4
jest: 30.2.0
lefthook: 2.0.2
- nitrogen: 0.30.2
+ nitrogen: 0.31.4
prettier: 3.6.2
react: 19.1.1
react-native: 0.82.1
react-native-builder-bob: 0.40.14
- react-native-nitro-modules: 0.30.2
+ react-native-nitro-modules: 0.31.4
semantic-release: 25.0.1
typescript: 5.9.3
peerDependencies:
@@ -12004,7 +12004,7 @@ __metadata:
languageName: node
linkType: hard
-"react-native-nitro-modules@npm:0.30.2, react-native-nitro-modules@npm:^0.30.2":
+"react-native-nitro-modules@npm:0.30.2":
version: 0.30.2
resolution: "react-native-nitro-modules@npm:0.30.2"
peerDependencies:
@@ -12014,6 +12014,16 @@ __metadata:
languageName: node
linkType: hard
+"react-native-nitro-modules@npm:0.31.4, react-native-nitro-modules@npm:^0.31.4":
+ version: 0.31.4
+ resolution: "react-native-nitro-modules@npm:0.31.4"
+ peerDependencies:
+ react: "*"
+ react-native: "*"
+ checksum: 9d251ec788eafb5c66033a1f376e2a8f9dfc8962a22e8511f6451bc50bf324549fd4e5113ee5bed59a993c0afc3288e8722d854239a33c00faae26848a211fde
+ languageName: node
+ linkType: hard
+
"react-native-reanimated@npm:4.1.3":
version: 4.1.3
resolution: "react-native-reanimated@npm:4.1.3"
@@ -12496,9 +12506,9 @@ __metadata:
linkType: hard
"sax@npm:>=0.6.0":
- version: 1.4.2
- resolution: "sax@npm:1.4.2"
- checksum: 2a036105f12793350f74e1a20e96c1fd4857353b65d6905c19bb9ce2ffa2c8df7a8ced901e65f34ba464001425a49d91178c47449056dd08a307e08cbe6e74f8
+ version: 1.4.3
+ resolution: "sax@npm:1.4.3"
+ checksum: 136a202eee9364f312fb1c6abadb045ef430a7468853f804758d8f2dc8d2560801245620e2bfd4ead2e332c025bef50865271974d142a0c26f69d5fc3de9baf1
languageName: node
linkType: hard
@@ -13520,9 +13530,9 @@ __metadata:
linkType: hard
"tinyexec@npm:^1.0.0":
- version: 1.0.1
- resolution: "tinyexec@npm:1.0.1"
- checksum: 40f5219abf891884863b085ebe5e8c8bf95bde802f6480f279588b355835ad1604fa01eada2afe90063b48b53cd4b0be5c37393980e23f06fd10689d92fb9586
+ version: 1.0.2
+ resolution: "tinyexec@npm:1.0.2"
+ checksum: af22de2191cc70bb782eef29bbba7cf6ac16664e550b547b0db68804f988eeb2c70e12fbb7d2d688ee994b28ba831d746e9eded98c3d10042fd3a9b8de208514
languageName: node
linkType: hard