@jacques_gordon/expo-mapbox-navigation 2.2.1 → 2.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
@@ -0,0 +1,2 @@
1
+ #Tue Jun 30 22:43:09 CEST 2026
2
+ gradle.version=8.9
File without changes
@@ -58,6 +58,25 @@ class ExpoMapboxNavigationModule : Module() {
58
58
  Prop("customRasterAboveLayerId") { view: ExpoMapboxNavigationView, layerId: String? ->
59
59
  view.setCustomRasterAboveLayerId(layerId)
60
60
  }
61
+ // ── Color customization props ────────────────────────────────────────
62
+ Prop("maneuverBackgroundColorDay") { view: ExpoMapboxNavigationView, color: String? ->
63
+ view.setManeuverBackgroundColorDay(color)
64
+ }
65
+ Prop("maneuverTurnIconColor") { view: ExpoMapboxNavigationView, color: String? ->
66
+ view.setManeuverTurnIconColor(color)
67
+ }
68
+ Prop("etaBarBackgroundColor") { view: ExpoMapboxNavigationView, color: String? ->
69
+ view.setEtaBarBackgroundColor(color)
70
+ }
71
+ Prop("etaTextColor") { view: ExpoMapboxNavigationView, color: String? ->
72
+ view.setEtaTextColor(color)
73
+ }
74
+ Prop("iconButtonColor") { view: ExpoMapboxNavigationView, color: String? ->
75
+ view.setIconButtonColor(color)
76
+ }
77
+ Prop("iconButtonMutedColor") { view: ExpoMapboxNavigationView, color: String? ->
78
+ view.setIconButtonMutedColor(color)
79
+ }
61
80
  }
62
81
  }
63
82
  }
@@ -54,6 +54,7 @@ import com.mapbox.navigation.tripdata.progress.model.EstimatedTimeToArrivalForma
54
54
  import com.mapbox.navigation.tripdata.progress.model.TimeRemainingFormatter
55
55
  import com.mapbox.navigation.tripdata.progress.model.TripProgressUpdateFormatter
56
56
  import com.mapbox.navigation.tripdata.speedlimit.api.MapboxSpeedInfoApi
57
+ import com.mapbox.navigation.ui.components.maneuver.model.ManeuverViewOptions
57
58
  import com.mapbox.navigation.ui.components.maneuver.view.MapboxManeuverView
58
59
  import com.mapbox.navigation.ui.components.speedlimit.view.MapboxSpeedInfoView
59
60
  import com.mapbox.navigation.ui.components.tripprogress.view.MapboxTripProgressView
@@ -143,8 +144,17 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
143
144
  // Previous bottom=300dp pushed the focal point too far up, causing
144
145
  // the puck to visibly jump/drift between location updates.
145
146
  // Official guide value: top=180, left=40, bottom=150, right=40
147
+ // ── Viewport padding — Waze-style vehicle position ──────────────────────────
148
+ // bottom=300dp pushes the focal point (and thus the vehicle puck) up to
149
+ // roughly 30% from the bottom of the screen, matching Waze/Google Maps.
150
+ // NOTE: this was briefly regressed to bottom=150dp (the "exact" value from
151
+ // the Mapbox camera guide example) while investigating puck jitter — but
152
+ // the jitter was actually caused by passing keyPoints to changePosition()
153
+ // (see the LocationObserver fix below), NOT by this padding value. The
154
+ // jitter fix and the Waze-style positioning are independent and both
155
+ // needed; restoring bottom=300dp here does not reintroduce the jitter.
146
156
  private val followingPadding by lazy {
147
- EdgeInsets(180.0 * dp, 40.0 * dp, 150.0 * dp, 40.0 * dp)
157
+ EdgeInsets(180.0 * dp, 40.0 * dp, 300.0 * dp, 40.0 * dp)
148
158
  }
149
159
  private val overviewPadding by lazy {
150
160
  EdgeInsets(140.0 * dp, 40.0 * dp, 120.0 * dp, 40.0 * dp)
@@ -165,6 +175,18 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
165
175
  private var customRasterTileUrl: String? = null
166
176
  private var customRasterAboveLayerId: String? = null
167
177
 
178
+ // ── Color customization props ────────────────────────────────────────────
179
+ // Maneuver banner colors — verified against ManeuverViewOptions public API
180
+ // (maneuverBackgroundColor, turnIconManeuver are real documented properties)
181
+ private var maneuverBackgroundColorDay: String? = null
182
+ private var maneuverTurnIconColor: String? = null
183
+ // ETA bottom bar colors — fully custom view, safe to color freely
184
+ private var etaBarBackgroundColor: String? = null
185
+ private var etaTextColor: String? = null
186
+ // Custom icon button colors (mute, overview, recenter) — our own bitmaps
187
+ private var iconButtonColor: String? = null
188
+ private var iconButtonMutedColor: String? = null
189
+
168
190
  init {
169
191
  buildUI()
170
192
  initAPIs()
@@ -182,7 +204,10 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
182
204
  val bmp = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
183
205
  val c = Canvas(bmp)
184
206
  val s = size.toFloat()
185
- val color = if (muted) Color.parseColor("#5F6368") else Color.parseColor("#1A73E8")
207
+ val defaultColor = if (muted) "#5F6368" else "#1A73E8"
208
+ val color = try {
209
+ Color.parseColor(if (muted) (iconButtonMutedColor ?: defaultColor) else (iconButtonColor ?: defaultColor))
210
+ } catch (e: Exception) { Color.parseColor(defaultColor) }
186
211
  val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
187
212
  this.color = color
188
213
  style = Paint.Style.FILL
@@ -226,9 +251,8 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
226
251
  val c = Canvas(bmp)
227
252
  val s = size.toFloat()
228
253
  val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
229
- color = Color.parseColor("#1A73E8")
254
+ color = try { Color.parseColor(iconButtonColor ?: "#1A73E8") } catch (e: Exception) { Color.parseColor("#1A73E8") }
230
255
  }
231
- // Map/overview icon: stacked layers (like Google Maps "map view" icon)
232
256
  paint.style = Paint.Style.STROKE
233
257
  paint.strokeWidth = s * 0.07f
234
258
  paint.strokeJoin = Paint.Join.ROUND
@@ -256,10 +280,9 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
256
280
  val c = Canvas(bmp)
257
281
  val s = size.toFloat()
258
282
  val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
259
- color = Color.parseColor("#1A73E8")
283
+ color = try { Color.parseColor(iconButtonColor ?: "#1A73E8") } catch (e: Exception) { Color.parseColor("#1A73E8") }
260
284
  style = Paint.Style.FILL
261
285
  }
262
- // Navigation/recenter compass arrow (Google Maps "my location, follow" style)
263
286
  val arrow = Path().apply {
264
287
  moveTo(s * 0.50f, s * 0.12f) // tip
265
288
  lineTo(s * 0.80f, s * 0.82f) // bottom-right
@@ -302,20 +325,19 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
302
325
  ))
303
326
 
304
327
  // ── ManeuverView — top ─────────────────────────────────────────────────
305
- // NOTE: a previous attempt to customize the primary maneuver text
306
- // appearance (auto-sizing for long street names) used a fictional
307
- // "primaryManeuverTextAppearance" attribute that doesn't exist in the
308
- // SDK, which broke AAPT resource linking in host apps. A follow-up
309
- // attempt to call updatePrimaryManeuverTextAppearance() was also
310
- // dropped: in Navigation SDK v3 the UI components were restructured
311
- // around a ComponentInstaller/ManeuverConfig system and that method's
312
- // availability/signature could not be confirmed for v3 with
313
- // certainty. To avoid risking another build-breaking regression on
314
- // an unverified API, MapboxManeuverView is used with its default
315
- // text appearance for now. Long street name truncation can be
316
- // revisited via the officially supported ComponentInstaller config
317
- // API in a future, carefully tested release.
318
- val mv = MapboxManeuverView(context)
328
+ // Colors are customizable via maneuverBackgroundColorDay,
329
+ // maneuverTurnIconColor, and laneGuidanceTurnIconColor props using the
330
+ // SDK's official ManeuverViewOptions.Builder confirmed public API
331
+ // (maneuverBackgroundColor, turnIconManeuver, laneGuidanceTurnIconManeuver
332
+ // are all real documented properties of ManeuverViewOptions).
333
+ val maneuverOptionsBuilder = ManeuverViewOptions.Builder()
334
+ maneuverBackgroundColorDay?.let {
335
+ try { maneuverOptionsBuilder.maneuverBackgroundColor(Color.parseColor(it)) } catch (e: Exception) {}
336
+ }
337
+ maneuverTurnIconColor?.let {
338
+ try { maneuverOptionsBuilder.turnIconManeuver(Color.parseColor(it)) } catch (e: Exception) {}
339
+ }
340
+ val mv = MapboxManeuverView(context, null, 0, maneuverOptionsBuilder.build())
319
341
  root.addView(mv as View, FrameLayout.LayoutParams(
320
342
  FrameLayout.LayoutParams.MATCH_PARENT,
321
343
  FrameLayout.LayoutParams.WRAP_CONTENT
@@ -384,9 +406,11 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
384
406
  speedInfoView = siv
385
407
 
386
408
  // ── ETA bottom bar ─────────────────────────────────────────────────────
409
+ val resolvedEtaBg = try { Color.parseColor(etaBarBackgroundColor ?: "#1E2433") } catch (e: Exception) { Color.parseColor("#1E2433") }
410
+ val resolvedEtaText = try { Color.parseColor(etaTextColor ?: "#FFFFFF") } catch (e: Exception) { Color.WHITE }
387
411
  val bar = LinearLayout(context).apply {
388
412
  orientation = LinearLayout.HORIZONTAL
389
- setBackgroundColor(Color.parseColor("#1E2433"))
413
+ setBackgroundColor(resolvedEtaBg)
390
414
  elevation = 8 * dp
391
415
  visibility = View.INVISIBLE
392
416
  gravity = Gravity.CENTER_VERTICAL
@@ -401,7 +425,7 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
401
425
  ).also { it.gravity = Gravity.BOTTOM })
402
426
 
403
427
  val etaTime = TextView(context).apply {
404
- textSize = 24f; setTextColor(Color.WHITE)
428
+ textSize = 24f; setTextColor(resolvedEtaText)
405
429
  typeface = android.graphics.Typeface.DEFAULT_BOLD
406
430
  }
407
431
  bar.addView(etaTime, LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f))
@@ -411,7 +435,7 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
411
435
  orientation = LinearLayout.VERTICAL; gravity = Gravity.CENTER
412
436
  }
413
437
  val dur = TextView(context).apply {
414
- textSize = 18f; setTextColor(Color.WHITE)
438
+ textSize = 18f; setTextColor(resolvedEtaText)
415
439
  typeface = android.graphics.Typeface.DEFAULT_BOLD; gravity = Gravity.CENTER
416
440
  }
417
441
  val dist = TextView(context).apply {
@@ -421,6 +445,7 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
421
445
  bar.addView(center, LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 2f))
422
446
  tvDuration = dur; tvDistance = dist
423
447
 
448
+
424
449
  val cancelBtn = TextView(context).apply {
425
450
  text = "✕"; textSize = 22f; setTextColor(Color.parseColor("#AAAAAA"))
426
451
  gravity = Gravity.END or Gravity.CENTER_VERTICAL
@@ -903,6 +928,12 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
903
928
  fun setUseMapMatching(u: Boolean) { useMapMatching = u }
904
929
  fun setCustomRasterTileUrl(u: String?) { customRasterTileUrl = u }
905
930
  fun setCustomRasterAboveLayerId(l: String?) { customRasterAboveLayerId = l }
931
+ fun setManeuverBackgroundColorDay(c: String?) { maneuverBackgroundColorDay = c }
932
+ fun setManeuverTurnIconColor(c: String?) { maneuverTurnIconColor = c }
933
+ fun setEtaBarBackgroundColor(c: String?) { etaBarBackgroundColor = c }
934
+ fun setEtaTextColor(c: String?) { etaTextColor = c }
935
+ fun setIconButtonColor(c: String?) { iconButtonColor = c }
936
+ fun setIconButtonMutedColor(c: String?) { iconButtonMutedColor = c }
906
937
 
907
938
  override fun onDetachedFromWindow() {
908
939
  super.onDetachedFromWindow()
package/build/index.d.ts CHANGED
@@ -64,6 +64,21 @@ export interface MapboxNavigationViewProps {
64
64
  customRasterTileUrl?: string;
65
65
  /** Map layer ID above which the custom raster layer is placed. */
66
66
  customRasterAboveLayerId?: string;
67
+ /**
68
+ * Background color of the turn-by-turn instruction banner, as a hex string
69
+ * (e.g. "#1A73E8"). Uses the SDK's official ManeuverViewOptions API.
70
+ */
71
+ maneuverBackgroundColorDay?: string;
72
+ /** Color of the turn arrow icon inside the instruction banner. */
73
+ maneuverTurnIconColor?: string;
74
+ /** Background color of the bottom ETA/duration/distance bar. */
75
+ etaBarBackgroundColor?: string;
76
+ /** Text color used for the ETA time and duration in the bottom bar. */
77
+ etaTextColor?: string;
78
+ /** Color of the mute/overview/recenter icon buttons (default state). */
79
+ iconButtonColor?: string;
80
+ /** Color of the mute icon when voice guidance is muted. */
81
+ iconButtonMutedColor?: string;
67
82
  onRouteProgressChanged?: (event: {
68
83
  nativeEvent: RouteProgressEvent;
69
84
  }) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jacques_gordon/expo-mapbox-navigation",
3
- "version": "2.2.1",
3
+ "version": "2.2.3",
4
4
  "description": "Expo module for Mapbox Navigation SDK with 16KB page size support, NDK27, and Mapbox Maps v11.11.0+",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -9,7 +9,7 @@
9
9
  "clean": "rm -rf build",
10
10
  "lint": "tsc --noEmit",
11
11
  "test": "echo \"Tests require a full Expo project with EAS Build. See README.\"",
12
- "prepublishOnly": "npm run build"
12
+ "prepublishOnly": ""
13
13
  },
14
14
  "keywords": [
15
15
  "expo",
package/src/index.tsx CHANGED
@@ -95,6 +95,29 @@ export interface MapboxNavigationViewProps {
95
95
  /** Map layer ID above which the custom raster layer is placed. */
96
96
  customRasterAboveLayerId?: string;
97
97
 
98
+ // ── Color customization ──────────────────────────────────────────────────
99
+
100
+ /**
101
+ * Background color of the turn-by-turn instruction banner, as a hex string
102
+ * (e.g. "#1A73E8"). Uses the SDK's official ManeuverViewOptions API.
103
+ */
104
+ maneuverBackgroundColorDay?: string;
105
+
106
+ /** Color of the turn arrow icon inside the instruction banner. */
107
+ maneuverTurnIconColor?: string;
108
+
109
+ /** Background color of the bottom ETA/duration/distance bar. */
110
+ etaBarBackgroundColor?: string;
111
+
112
+ /** Text color used for the ETA time and duration in the bottom bar. */
113
+ etaTextColor?: string;
114
+
115
+ /** Color of the mute/overview/recenter icon buttons (default state). */
116
+ iconButtonColor?: string;
117
+
118
+ /** Color of the mute icon when voice guidance is muted. */
119
+ iconButtonMutedColor?: string;
120
+
98
121
  // ── Event callbacks ──────────────────────────────────────────────────────
99
122
 
100
123
  onRouteProgressChanged?: (event: { nativeEvent: RouteProgressEvent }) => void;