diff --git a/example/src/App.tsx b/example/src/App.tsx
index d91c528..c0c840d 100644
--- a/example/src/App.tsx
+++ b/example/src/App.tsx
@@ -23,8 +23,9 @@ import {
} from '@react-navigation/native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { createStackNavigator } from '@react-navigation/stack';
-import { View, Button, Text } from 'react-native';
+import { View, Text } from 'react-native';
import { CommonStyles } from './styles/components';
+import { ExampleAppButton } from './controls/ExampleAppButton';
import NavigationScreen from './screens/NavigationScreen';
import MultipleMapsScreen from './screens/MultipleMapsScreen';
import MapIdScreen from './screens/MapIdScreen';
@@ -78,19 +79,19 @@ const HomeScreen = () => {
{/* Spacer */}
-
-
-
diff --git a/example/src/controls/ExampleAppButton.tsx b/example/src/controls/ExampleAppButton.tsx
new file mode 100644
index 0000000..6c82257
--- /dev/null
+++ b/example/src/controls/ExampleAppButton.tsx
@@ -0,0 +1,96 @@
+/**
+ * Copyright 2025 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from 'react';
+import { Pressable, Text, StyleSheet } from 'react-native';
+import { Colors, BorderRadius, Typography, Spacing } from '../styles/theme';
+
+type ExampleAppButtonProps = {
+ title: string;
+ onPress: () => void;
+ backgroundColor?: string;
+ pressedBackgroundColor?: string;
+ textColor?: string;
+ disabled?: boolean;
+ testID?: string;
+};
+
+export const ExampleAppButton = ({
+ title,
+ onPress,
+ backgroundColor,
+ pressedBackgroundColor: pressedColor,
+ textColor: textColor,
+ disabled = false,
+ testID,
+}: ExampleAppButtonProps) => {
+ const resolvedBackground = disabled
+ ? Colors.buttonDisabled
+ : (backgroundColor ?? Colors.button);
+ const resolvedPressed = disabled
+ ? Colors.buttonDisabled
+ : (pressedColor ?? Colors.buttonPressed);
+ const resolvedTextColor = disabled
+ ? Colors.textDisabled
+ : (textColor ?? Colors.buttonText);
+
+ return (
+ [
+ styles.buttonBase,
+ {
+ backgroundColor:
+ pressed && !disabled ? resolvedPressed : resolvedBackground,
+ },
+ disabled && styles.buttonDisabled,
+ ]}
+ >
+
+ {title}
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ buttonBase: {
+ paddingVertical: Spacing.md,
+ paddingHorizontal: Spacing.lg,
+ borderRadius: BorderRadius.lg,
+ alignItems: 'center',
+ marginVertical: Spacing.xs,
+ },
+ buttonText: {
+ fontWeight: Typography.fontWeight.semibold,
+ fontSize: Typography.fontSize.md,
+ },
+ buttonDisabled: {
+ opacity: 0.6,
+ },
+});
diff --git a/example/src/controls/mapsControls.tsx b/example/src/controls/mapsControls.tsx
index 3f3b1bb..54d736d 100644
--- a/example/src/controls/mapsControls.tsx
+++ b/example/src/controls/mapsControls.tsx
@@ -16,7 +16,8 @@
import React, { useEffect, useState } from 'react';
-import { Button, Text, TextInput, View } from 'react-native';
+import { Text, TextInput, View } from 'react-native';
+import { ExampleAppButton } from './ExampleAppButton';
import SelectDropdown from 'react-native-select-dropdown';
import { ControlStyles } from '../styles/components';
@@ -255,35 +256,41 @@ const MapsControls: React.FC = ({
placeholderTextColor="#000"
keyboardType="numeric"
/>
-
-
+ {
setZoom((zoom ?? defaultZoom) + 1);
}}
/>
- {
setZoom((zoom ?? defaultZoom) - 1);
}}
/>
- addMarker()} />
- addCustomMarker()} />
-
-
-
-
-
-
- addMarker()} />
+ addCustomMarker()}
+ />
+
+
+
+
+
+
+
-
+
Location marker
- {
setEnableLocationMarker(!enableLocationMarker);
@@ -325,7 +332,7 @@ const MapsControls: React.FC = ({
Custom map paddings
-
diff --git a/example/src/controls/navigationControls.tsx b/example/src/controls/navigationControls.tsx
index 1d9d067..0ec8457 100644
--- a/example/src/controls/navigationControls.tsx
+++ b/example/src/controls/navigationControls.tsx
@@ -15,7 +15,8 @@
*/
import React, { useState } from 'react';
-import { Alert, Button, Platform, Text, TextInput, View } from 'react-native';
+import { Alert, Platform, Text, TextInput, View } from 'react-native';
+import { ExampleAppButton } from './ExampleAppButton';
import {
CameraPerspective,
NavigationNightMode,
@@ -349,48 +350,72 @@ const NavigationControls: React.FC = ({
placeholderTextColor="#000"
keyboardType="numeric"
/>
-
-
-
+
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
Toggle trip progress bar
- {
setTripProgressBarEnabled(!tripProgressBarEnabled);
@@ -402,7 +427,7 @@ const NavigationControls: React.FC = ({
Toggle report incident button
- {
setReportIncidentButtonEnabled(!reportIncidentButtonEnabled);
@@ -414,7 +439,7 @@ const NavigationControls: React.FC = ({
Speed limit icon
- {
toggleSpeedLimitIconEnabled(!speedLimitIconEnabled);
@@ -423,7 +448,7 @@ const NavigationControls: React.FC = ({
Speedometer
- {
toggleSpeedometerEnabled(!speedometerEnabled);
@@ -432,7 +457,7 @@ const NavigationControls: React.FC = ({
Traffic incidents card
- {
toggleTrafficIncidentCardsEnabled(!trafficIncidentCardsEnabled);
@@ -441,7 +466,7 @@ const NavigationControls: React.FC = ({
Navigation UI
- {
toggleNavigationUiEnabled(!navigationUiEnabled);
@@ -450,7 +475,7 @@ const NavigationControls: React.FC = ({
Turn-by-turn logging
- {
toggleTurnByTurnLoggingEnabled(!turnByTurnLoggingEnabled);
@@ -460,7 +485,7 @@ const NavigationControls: React.FC = ({
{Platform.OS === 'ios' ? (
Background location updates
- {
toggleBackgroundLocationUpdatesEnabled(
@@ -472,7 +497,7 @@ const NavigationControls: React.FC = ({
) : null}
Recenter button
- {
toggleRecenterButtonEnabled(!recenterButtonEnabled);
@@ -481,7 +506,7 @@ const NavigationControls: React.FC = ({
Header enabled
- {
toggleHeaderEnabled(!headerEnabled);
@@ -490,7 +515,7 @@ const NavigationControls: React.FC = ({
Footer enabled
- {
toggleFooterEnabled(!footerEnabled);
diff --git a/example/src/helpers/overlayModal.tsx b/example/src/helpers/overlayModal.tsx
index 066a7b6..26855da 100644
--- a/example/src/helpers/overlayModal.tsx
+++ b/example/src/helpers/overlayModal.tsx
@@ -15,15 +15,8 @@
*/
import React, { type ReactNode } from 'react';
-import {
- View,
- Modal,
- Text,
- TouchableOpacity,
- StyleSheet,
- TouchableWithoutFeedback,
- ScrollView,
-} from 'react-native';
+import { View, Modal, StyleSheet, Pressable, ScrollView } from 'react-native';
+import { ExampleAppButton } from '../controls/ExampleAppButton';
interface OverlayModalProps {
visible: boolean;
@@ -50,27 +43,26 @@ const OverlayModal: React.FC = ({
animationType="slide"
onRequestClose={closeOverlay}
>
-
-
-
-
-
- {children}
-
-
- Close
-
-
-
+
+
+
+
+ {children}
+
+
+
+
-
+
);
};
@@ -80,6 +72,9 @@ const styles = StyleSheet.create({
flex: 1,
justifyContent: 'flex-end',
},
+ overlayTouchable: {
+ ...StyleSheet.absoluteFillObject,
+ },
modalContent: {
height: '60%',
backgroundColor: '#fff',
@@ -98,15 +93,23 @@ const styles = StyleSheet.create({
scrollContainer: {
flexGrow: 1,
},
- closeButton: {
- padding: 10,
- backgroundColor: '#dc3545',
- borderRadius: 5,
- alignItems: 'center',
+ scrollContentContainer: {
+ flexGrow: 1,
+ minHeight: '100%',
},
- closeButtonText: {
- color: '#fff',
- fontSize: 16,
+ scrollContent: {
+ flex: 1,
+ },
+ closeButtonContainer: {
+ marginTop: 8,
+ shadowColor: '#000',
+ shadowOffset: {
+ width: 0,
+ height: -2,
+ },
+ shadowOpacity: 0.15,
+ shadowRadius: 4,
+ elevation: 4,
},
});
diff --git a/example/src/screens/IntegrationTestsScreen.tsx b/example/src/screens/IntegrationTestsScreen.tsx
index f1b51ee..ed56fe4 100644
--- a/example/src/screens/IntegrationTestsScreen.tsx
+++ b/example/src/screens/IntegrationTestsScreen.tsx
@@ -16,7 +16,8 @@
*/
import React, { useState, useMemo, useCallback } from 'react';
-import { Button, Text, View, useWindowDimensions } from 'react-native';
+import { Text, View, useWindowDimensions } from 'react-native';
+import { ExampleAppButton } from '../controls/ExampleAppButton';
import Snackbar from 'react-native-snackbar';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
@@ -252,7 +253,7 @@ const IntegrationTestsScreen = () => {
Test status: {testStatusString}
Test result: {testResult}
{failureMessage}
- {
resetTestState();
@@ -260,12 +261,12 @@ const IntegrationTestsScreen = () => {
/>
- {
setIsOverlayOpen(true);
}}
+ testID="tests_menu_button"
/>
{
}}
height={overlayMinHeight}
>
- {
runTest('testNavigationSessionInitialization');
}}
+ testID="testNavigationSessionInitialization"
/>
- {
runTest('testMapInitialization');
}}
+ testID="testMapInitialization"
/>
- {
runTest('testNavigationToSingleDestination');
}}
+ testID="testNavigationToSingleDestination"
/>
- {
runTest('testNavigationToMultipleDestination');
}}
+ testID="testNavigationToMultipleDestination"
/>
- {
runTest('testRouteSegments');
}}
+ testID="testRouteSegments"
/>
- {
runTest('testGetCurrentTimeAndDistance');
}}
+ testID="testGetCurrentTimeAndDistance"
/>
- {
runTest('testMoveCamera');
}}
+ testID="testMoveCamera"
/>
- {
runTest('testTiltZoomBearingCamera');
}}
+ testID="testTiltZoomBearingCamera"
/>
- {
runTest('testOnRemainingTimeOrDistanceChanged');
}}
+ testID="testOnRemainingTimeOrDistanceChanged"
/>
- {
runTest('testOnArrival');
}}
+ testID="testOnArrival"
/>
- {
runTest('testOnRouteChanged');
}}
+ testID="testOnRouteChanged"
/>
- {
runTest('testNavigationStateGuards');
}}
+ testID="testNavigationStateGuards"
/>
- {
runTest('testStartGuidanceWithoutDestinations');
}}
+ testID="testStartGuidanceWithoutDestinations"
/>
diff --git a/example/src/screens/MapIdScreen.tsx b/example/src/screens/MapIdScreen.tsx
index c3dc13c..215e05a 100644
--- a/example/src/screens/MapIdScreen.tsx
+++ b/example/src/screens/MapIdScreen.tsx
@@ -19,11 +19,11 @@ import {
View,
Text,
TextInput,
- Button,
StyleSheet,
Alert,
ScrollView,
} from 'react-native';
+import { ExampleAppButton } from '../controls/ExampleAppButton';
import { CommonStyles, MapStyles } from '../styles/components';
import {
NavigationView,
@@ -226,7 +226,10 @@ const MapIdScreen = () => {
-
+
@@ -246,7 +249,7 @@ const MapIdScreen = () => {
Map ID: {confirmedMapId || '(Default styling)'}
-
+
{/* NavigationView */}
@@ -254,7 +257,7 @@ const MapIdScreen = () => {
Navigation View
- {
toggleNavigationUiEnabled(!navigationUiEnabled)
}
/>
-
@@ -298,7 +301,7 @@ const MapIdScreen = () => {
-
diff --git a/example/src/screens/MultipleMapsScreen.tsx b/example/src/screens/MultipleMapsScreen.tsx
index 9b710ab..9e9db5a 100644
--- a/example/src/screens/MultipleMapsScreen.tsx
+++ b/example/src/screens/MultipleMapsScreen.tsx
@@ -21,7 +21,8 @@ import React, {
useCallback,
useRef,
} from 'react';
-import { Button, View } from 'react-native';
+import { View } from 'react-native';
+import { ExampleAppButton } from '../controls/ExampleAppButton';
import PagerView, {
type PagerViewOnPageSelectedEvent,
} from 'react-native-pager-view';
@@ -313,7 +314,7 @@ const MultipleMapsScreen = () => {
return arePermissionsApproved ? (
- setMapsVisible(v => !v)}
/>
@@ -322,12 +323,12 @@ const MultipleMapsScreen = () => {
{mapsVisible && (
- goToPage(0)}
disabled={currentPage === 0}
/>
- goToPage(1)}
disabled={currentPage === 1}
@@ -354,12 +355,15 @@ const MultipleMapsScreen = () => {
onNavigationViewControllerCreated={setNavigationViewController1}
/>
-
-
+
{/* Page 2: MapView */}
@@ -372,7 +376,10 @@ const MultipleMapsScreen = () => {
/>
{currentPage === 1 && (
-
+
)}
diff --git a/example/src/screens/NavigationScreen.tsx b/example/src/screens/NavigationScreen.tsx
index 3c0dcc2..9974dbb 100644
--- a/example/src/screens/NavigationScreen.tsx
+++ b/example/src/screens/NavigationScreen.tsx
@@ -15,7 +15,8 @@
*/
import React, { useEffect, useState, useMemo, useCallback } from 'react';
-import { Button, View } from 'react-native';
+import { View } from 'react-native';
+import { ExampleAppButton } from '../controls/ExampleAppButton';
import Snackbar from 'react-native-snackbar';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
@@ -357,14 +358,17 @@ const NavigationScreen = () => {
)}
-
-
+
{mapViewAutoAvailable && (
-
+
)}
diff --git a/example/src/styles/theme.ts b/example/src/styles/theme.ts
index 37a14a3..9a22d05 100644
--- a/example/src/styles/theme.ts
+++ b/example/src/styles/theme.ts
@@ -42,7 +42,9 @@ export const Colors = {
// Interactive colors
button: '#2196f3',
+ buttonPressed: '#1c89e1ff',
buttonDisabled: '#cccccc',
+ buttonText: '#ffffff',
// Dropdown selection colors
dropdownSelected: '#D2D9DF',