expo-dev-menu 58.0.8 → 58.0.10

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.
package/CHANGELOG.md CHANGED
@@ -1,14 +1,18 @@
1
1
  # Changelog
2
2
 
3
- ## Unpublished
3
+ ## 58.0.10
4
4
 
5
- ### 🛠 Breaking changes
5
+ ### Patch Changes
6
6
 
7
- ### 🎉 New features
7
+ - [iOS] Disable the vertical bar while the dev menu is open so the sheet fills the full width on iPhone Duo. ([#50900](https://github.com/expo/expo/pull/50900) by [@alanjhughes](https://github.com/alanjhughes))
8
8
 
9
- ### 🐛 Bug fixes
9
+ ## 58.0.9
10
10
 
11
- ### 💡 Others
11
+ ### Patch Changes
12
+
13
+ - Force-bump all packages, due to migration to changesets. ([#50762](https://github.com/expo/expo/pull/50762) by [@kitten](https://github.com/kitten))
14
+ - Updated dependencies. ([#50762](https://github.com/expo/expo/pull/50762))
15
+ - expo-dev-menu-interface@58.0.1
12
16
 
13
17
  ## 58.0.8 — 2026-09-28
14
18
 
@@ -12,7 +12,7 @@ apply plugin: 'expo-module-gradle-plugin'
12
12
  apply plugin: 'org.jetbrains.kotlin.plugin.compose'
13
13
 
14
14
  group = 'host.exp.exponent'
15
- version = '58.0.8'
15
+ version = '58.0.10'
16
16
 
17
17
  def hasDevLauncher = findProject(":expo-dev-launcher") != null
18
18
  def configureInRelease = findProperty("expo.devmenu.configureInRelease") == "true"
@@ -29,7 +29,7 @@ android {
29
29
 
30
30
  defaultConfig {
31
31
  versionCode 10
32
- versionName '58.0.8'
32
+ versionName '58.0.10'
33
33
  }
34
34
 
35
35
  buildTypes {
@@ -69,7 +69,11 @@ internal class CommonRippleNode(
69
69
  override fun addRipple(interaction: PressInteraction.Press, size: Size, targetRadius: Float) {
70
70
  // Finish existing ripples
71
71
  ripples.forEach { _, ripple -> ripple.finish() }
72
- val origin = if (bounded) interaction.pressPosition else null
72
+ val origin = if (bounded) {
73
+ interaction.pressPosition
74
+ } else {
75
+ null
76
+ }
73
77
  val rippleAnimation =
74
78
  RippleAnimation(origin = origin, radius = targetRadius, bounded = bounded)
75
79
  ripples[interaction] = rippleAnimation
@@ -186,7 +190,9 @@ internal class AndroidRippleNode(
186
190
  }
187
191
 
188
192
  private fun getOrCreateRippleContainer(): RippleContainer {
189
- if (rippleContainer != null) return rippleContainer!!
193
+ if (rippleContainer != null) {
194
+ return rippleContainer!!
195
+ }
190
196
  val view = findNearestViewGroup(currentValueOf(LocalView))
191
197
  rippleContainer = createAndAttachRippleContainerIfNeeded(view)
192
198
  return rippleContainer!!
@@ -26,13 +26,25 @@ public class RippleAlpha(
26
26
  public val pressedAlpha: Float
27
27
  ) {
28
28
  override fun equals(other: Any?): Boolean {
29
- if (this === other) return true
30
- if (other !is RippleAlpha) return false
29
+ if (this === other) {
30
+ return true
31
+ }
32
+ if (other !is RippleAlpha) {
33
+ return false
34
+ }
31
35
 
32
- if (draggedAlpha != other.draggedAlpha) return false
33
- if (focusedAlpha != other.focusedAlpha) return false
34
- if (hoveredAlpha != other.hoveredAlpha) return false
35
- if (pressedAlpha != other.pressedAlpha) return false
36
+ if (draggedAlpha != other.draggedAlpha) {
37
+ return false
38
+ }
39
+ if (focusedAlpha != other.focusedAlpha) {
40
+ return false
41
+ }
42
+ if (hoveredAlpha != other.hoveredAlpha) {
43
+ return false
44
+ }
45
+ if (pressedAlpha != other.pressedAlpha) {
46
+ return false
47
+ }
36
48
 
37
49
  return true
38
50
  }
@@ -77,7 +77,11 @@ fun ripple(
77
77
  color: Color = Color.Unspecified
78
78
  ): IndicationNodeFactory {
79
79
  return if (radius == Dp.Unspecified && color == Color.Unspecified) {
80
- if (bounded) return DefaultBoundedRipple else DefaultUnboundedRipple
80
+ if (bounded) {
81
+ return DefaultBoundedRipple
82
+ } else {
83
+ DefaultUnboundedRipple
84
+ }
81
85
  } else {
82
86
  RippleNodeFactory(bounded, radius, color)
83
87
  }
@@ -207,11 +211,19 @@ class RippleConfiguration(
207
211
  val rippleAlpha: RippleAlpha? = null
208
212
  ) {
209
213
  override fun equals(other: Any?): Boolean {
210
- if (this === other) return true
211
- if (other !is RippleConfiguration) return false
214
+ if (this === other) {
215
+ return true
216
+ }
217
+ if (other !is RippleConfiguration) {
218
+ return false
219
+ }
212
220
 
213
- if (color != other.color) return false
214
- if (rippleAlpha != other.rippleAlpha) return false
221
+ if (color != other.color) {
222
+ return false
223
+ }
224
+ if (rippleAlpha != other.rippleAlpha) {
225
+ return false
226
+ }
215
227
 
216
228
  return true
217
229
  }
@@ -249,12 +261,22 @@ private constructor(
249
261
  }
250
262
 
251
263
  override fun equals(other: Any?): Boolean {
252
- if (this === other) return true
253
- if (other !is RippleNodeFactory) return false
264
+ if (this === other) {
265
+ return true
266
+ }
267
+ if (other !is RippleNodeFactory) {
268
+ return false
269
+ }
254
270
 
255
- if (bounded != other.bounded) return false
256
- if (radius != other.radius) return false
257
- if (colorProducer != other.colorProducer) return false
271
+ if (bounded != other.bounded) {
272
+ return false
273
+ }
274
+ if (radius != other.radius) {
275
+ return false
276
+ }
277
+ if (colorProducer != other.colorProducer) {
278
+ return false
279
+ }
258
280
  return color == other.color
259
281
  }
260
282
 
@@ -294,7 +316,9 @@ private class DelegatingThemeAwareRippleNode(
294
316
  if (configuration == null) {
295
317
  removeRipple()
296
318
  } else {
297
- if (rippleNode == null) attachNewRipple()
319
+ if (rippleNode == null) {
320
+ attachNewRipple()
321
+ }
298
322
  }
299
323
  }
300
324
  }
@@ -227,7 +227,11 @@ internal class RippleHostView(context: Context) : View(context) {
227
227
  }
228
228
  postDelayed(resetRippleRunnable, ResetRippleDelayDuration)
229
229
  } else {
230
- val state = if (pressed) PressedState else RestingState
230
+ val state = if (pressed) {
231
+ PressedState
232
+ } else {
233
+ RestingState
234
+ }
231
235
  ripple?.state = state
232
236
  }
233
237
  lastRippleStateChangeTimeMillis = currentTime
@@ -276,7 +280,11 @@ private class UnprojectedRipple(private val bounded: Boolean) :
276
280
  // The color of the mask here doesn't matter - we just need a mask to draw the bounded
277
281
  // ripple
278
282
  // against
279
- /* mask */ if (bounded) ColorDrawable(android.graphics.Color.WHITE) else null
283
+ /* mask */ if (bounded) {
284
+ ColorDrawable(android.graphics.Color.WHITE)
285
+ } else {
286
+ null
287
+ }
280
288
  ) {
281
289
  /**
282
290
  * Store the ripple color so we can compare it later, as there is no way to get the currently
@@ -41,8 +41,16 @@ class FabState(
41
41
 
42
42
  fun savePosition(offset: Offset) {
43
43
  // Store position as 0–1 ratios within the safe area so it survives screen size changes
44
- val normalizedX = if (fabAreaBounds.x > 0f) offset.x / fabAreaBounds.x else 0f
45
- val normalizedY = if (fabAreaBounds.y > 0f) offset.y / fabAreaBounds.y else 0f
44
+ val normalizedX = if (fabAreaBounds.x > 0f) {
45
+ offset.x / fabAreaBounds.x
46
+ } else {
47
+ 0f
48
+ }
49
+ val normalizedY = if (fabAreaBounds.y > 0f) {
50
+ offset.y / fabAreaBounds.y
51
+ } else {
52
+ 0f
53
+ }
46
54
 
47
55
  prefs.edit {
48
56
  putFloat(FAB_POSITION_X, normalizedX)
@@ -42,17 +42,29 @@ fun FloatingActionButtonContent(
42
42
  showLabel: Boolean = true
43
43
  ) {
44
44
  val scale by animateFloatAsState(
45
- targetValue = if (isPressed && !isDragging) 0.9f else 1f,
45
+ targetValue = if (isPressed && !isDragging) {
46
+ 0.9f
47
+ } else {
48
+ 1f
49
+ },
46
50
  label = "pressScale"
47
51
  )
48
52
 
49
53
  val idleAlpha by animateFloatAsState(
50
- targetValue = if (isIdle) 0.5f else 1f,
54
+ targetValue = if (isIdle) {
55
+ 0.5f
56
+ } else {
57
+ 1f
58
+ },
51
59
  label = "idleAlpha"
52
60
  )
53
61
 
54
62
  val idleSaturation by animateFloatAsState(
55
- targetValue = if (isIdle) 0f else 1f,
63
+ targetValue = if (isIdle) {
64
+ 0f
65
+ } else {
66
+ 1f
67
+ },
56
68
  label = "idleSaturation"
57
69
  )
58
70
 
@@ -109,7 +109,11 @@ fun MovableFloatingActionButton(
109
109
  if (state.isOpen) {
110
110
  fab.restingOffset = fab.animatedOffset.value
111
111
  val isOnLeftSide = fab.animatedOffset.value.x < fab.fabAreaBounds.x / 2f
112
- val offScreenX = if (isOnLeftSide) -totalFabSizePx.x else constraints.maxWidth.toFloat()
112
+ val offScreenX = if (isOnLeftSide) {
113
+ -totalFabSizePx.x
114
+ } else {
115
+ constraints.maxWidth.toFloat()
116
+ }
113
117
  fab.animatedOffset.animateTo(
114
118
  targetValue = Offset(offScreenX, fab.animatedOffset.value.y),
115
119
  animationSpec = tween(durationMillis = 500)
@@ -8,7 +8,11 @@ import android.net.Uri
8
8
  * Keep in sync with `packages/expo-dev-menu/ios/Launch/ExpoLauncherURL.swift`.
9
9
  */
10
10
  class ExpoLauncherUrl(val url: Uri) {
11
- private val paramNames: Set<String> = if (url.isHierarchical) url.queryParameterNames else emptySet()
11
+ private val paramNames: Set<String> = if (url.isHierarchical) {
12
+ url.queryParameterNames
13
+ } else {
14
+ emptySet()
15
+ }
12
16
  private val hasReservedParams = paramNames.any { it.startsWith(RESERVED_PREFIX) }
13
17
 
14
18
  val isLegacyHost = url.host == LEGACY_HOST
@@ -47,7 +51,9 @@ class ExpoLauncherUrl(val url: Uri) {
47
51
 
48
52
  /** `__expo_<name>`, or the [legacy] param next to the legacy host. */
49
53
  private fun param(name: String, legacy: String? = null): String? {
50
- if (!url.isHierarchical) return null
54
+ if (!url.isHierarchical) {
55
+ return null
56
+ }
51
57
  return url.getQueryParameter(RESERVED_PREFIX + name)
52
58
  ?: legacy?.takeIf { isLegacyHost }?.let(url::getQueryParameter)
53
59
  }
@@ -42,6 +42,13 @@ class DevMenuViewController: UIViewController {
42
42
  }
43
43
  #endif
44
44
 
45
+ #if canImport(SwiftUICore, _version: 8.0.85) && os(iOS)
46
+ @available(iOS 27.1, *)
47
+ override var preferredVerticalBarBehavior: UIVerticalBarBehavior {
48
+ return .disabled
49
+ }
50
+ #endif
51
+
45
52
  private func setupSwiftUIView() {
46
53
  let rootView = DevMenuRootView()
47
54
  let hostingController = UIHostingController(rootView: rootView)
@@ -63,7 +63,8 @@ struct HeaderView: View {
63
63
  .task {
64
64
  await loadIcon(from: viewModel.appInfo?.appIcon)
65
65
  }
66
- .padding()
66
+ .padding([.horizontal, .bottom])
67
+ .padding(.top, 24)
67
68
  }
68
69
 
69
70
  private func loadIcon(from path: String?) async {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-dev-menu",
3
- "version": "58.0.8",
3
+ "version": "58.0.10",
4
4
  "description": "Expo/React Native module with the developer menu.",
5
5
  "keywords": [
6
6
  "dev",
@@ -24,23 +24,22 @@
24
24
  "main": "build/DevMenu.js",
25
25
  "types": "build/DevMenu.d.ts",
26
26
  "dependencies": {
27
- "expo-dev-menu-interface": "~58.0.0"
27
+ "expo-dev-menu-interface": "~58.0.1"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@babel/preset-typescript": "^7.7.4",
31
- "@testing-library/react-native": "^13.3.0",
31
+ "@testing-library/react-native": "^14.0.1",
32
32
  "@types/jest": "^29.2.1",
33
33
  "@types/node": "^22.14.0",
34
- "babel-preset-expo": "58.0.5",
35
- "expo-module-scripts": "56.0.3",
34
+ "babel-preset-expo": "58.0.8",
35
+ "expo-module-scripts": "56.0.5",
36
36
  "react": "19.3.0",
37
- "react-native": "0.88.0-rc.2"
37
+ "react-native": "0.88.0-rc.3"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "expo": "*",
41
41
  "react-native": "*"
42
42
  },
43
- "gitHead": "74f6d2b90bc50bd8df7b160d6e6b2204b37a8ce7",
44
43
  "scripts": {
45
44
  "build": "pnpm run build:lib && pnpm run build:plugin",
46
45
  "build:lib": "expo-build src",