expo-dev-menu 57.0.0 → 57.0.1
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 +10 -0
- package/android/build.gradle +2 -2
- package/android/src/debug/java/expo/modules/devmenu/DevMenuPreferences.kt +9 -0
- package/ios/FAB/DevMenuFABView.swift +28 -18
- package/ios/SwiftUI/DevMenuAppInfo.swift +4 -3
- package/ios/SwiftUI/DevMenuRootView.swift +2 -0
- package/ios/SwiftUI/DevMenuViewModel.swift +6 -2
- package/ios/SwiftUI/HostUrl.swift +4 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,16 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 57.0.1 — 2026-06-25
|
|
14
|
+
|
|
15
|
+
### 🎉 New features
|
|
16
|
+
|
|
17
|
+
- Add a `tryToLaunchLastBundle` preference backing the dev launcher auto-launch toggle. ([#47131](https://github.com/expo/expo/pull/47131) by [@alanjhughes](https://github.com/alanjhughes))
|
|
18
|
+
|
|
19
|
+
### 🐛 Bug fixes
|
|
20
|
+
|
|
21
|
+
- [iOS] Show the floating Tools button at its final position instead of animating in from the top-left corner. ([#46762](https://github.com/expo/expo/pull/46762) by [@alanjhughes](https://github.com/alanjhughes))
|
|
22
|
+
|
|
13
23
|
## 57.0.0 — 2026-06-25
|
|
14
24
|
|
|
15
25
|
### 🐛 Bug fixes
|
package/android/build.gradle
CHANGED
|
@@ -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 = '57.0.
|
|
15
|
+
version = '57.0.1'
|
|
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 '57.0.
|
|
32
|
+
versionName '57.0.1'
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
buildTypes {
|
|
@@ -49,6 +49,11 @@ interface DevMenuPreferences {
|
|
|
49
49
|
* Whether to show a floating action button that pulls up the DevMenu at launch.
|
|
50
50
|
*/
|
|
51
51
|
var showFab: Boolean
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Whether to try to launch the most recently opened project at startup instead of showing the launcher.
|
|
55
|
+
*/
|
|
56
|
+
var tryToLaunchLastBundle: Boolean
|
|
52
57
|
}
|
|
53
58
|
|
|
54
59
|
class DevMenuDefaultPreferences(
|
|
@@ -68,6 +73,7 @@ class DevMenuDefaultPreferences(
|
|
|
68
73
|
private val fabDefault = metaDataBool("EXDevMenuShowFloatingActionButton", true)
|
|
69
74
|
private val showsAtLaunchDefault = metaDataBool("EXDevMenuShowsAtLaunch", true)
|
|
70
75
|
private val isOnboardingFinishedDefault = metaDataBool("EXDevMenuIsOnboardingFinished", false)
|
|
76
|
+
private val tryToLaunchLastBundleDefault = metaDataBool("DEV_CLIENT_TRY_TO_LAUNCH_LAST_BUNDLE", true)
|
|
71
77
|
|
|
72
78
|
private val listeners = mutableListOf<() -> Unit>()
|
|
73
79
|
|
|
@@ -108,4 +114,7 @@ class DevMenuDefaultPreferences(
|
|
|
108
114
|
|
|
109
115
|
override var showFab: Boolean
|
|
110
116
|
by preferences(sharedPreferences, fabDefault)
|
|
117
|
+
|
|
118
|
+
override var tryToLaunchLastBundle: Boolean
|
|
119
|
+
by preferences(sharedPreferences, tryToLaunchLastBundleDefault)
|
|
111
120
|
}
|
|
@@ -134,6 +134,7 @@ struct DevMenuFABView: View {
|
|
|
134
134
|
@State private var isDragging = false
|
|
135
135
|
@State private var isPressed = false
|
|
136
136
|
@State private var dragStartPosition: CGPoint = .zero
|
|
137
|
+
@State private var didPosition = false
|
|
137
138
|
|
|
138
139
|
// Get safe area from window since .ignoresSafeArea() may zero out geometry values
|
|
139
140
|
private var windowSafeArea: UIEdgeInsets {
|
|
@@ -169,23 +170,7 @@ struct DevMenuFABView: View {
|
|
|
169
170
|
.position(x: currentFrame.midX, y: currentFrame.midY)
|
|
170
171
|
.gesture(dragGesture(bounds: geometry.size, safeArea: safeArea))
|
|
171
172
|
.onAppear {
|
|
172
|
-
|
|
173
|
-
if let storedPos = Self.loadStoredPosition() {
|
|
174
|
-
let margin = FABConstants.margin
|
|
175
|
-
let minX = margin / 2
|
|
176
|
-
let maxX = geometry.size.width - fabSize.width - margin / 2
|
|
177
|
-
let minY = safeArea.top + FABConstants.verticalPadding
|
|
178
|
-
let maxY = geometry.size.height - fabSize.height - safeArea.bottom - FABConstants.verticalPadding
|
|
179
|
-
|
|
180
|
-
initialPos = CGPoint(
|
|
181
|
-
x: storedPos.x.clamped(to: minX...maxX),
|
|
182
|
-
y: storedPos.y.clamped(to: minY...maxY)
|
|
183
|
-
)
|
|
184
|
-
} else {
|
|
185
|
-
initialPos = defaultPosition(bounds: geometry.size, safeArea: safeArea)
|
|
186
|
-
}
|
|
187
|
-
position = initialPos
|
|
188
|
-
onFrameChange(CGRect(origin: initialPos, size: fabSize))
|
|
173
|
+
placeInitially(bounds: geometry.size, safeArea: safeArea)
|
|
189
174
|
}
|
|
190
175
|
.onChange(of: geometry.size) { newSize in
|
|
191
176
|
let newPos = snapToEdge(
|
|
@@ -197,7 +182,7 @@ struct DevMenuFABView: View {
|
|
|
197
182
|
position = newPos
|
|
198
183
|
onFrameChange(CGRect(origin: newPos, size: fabSize))
|
|
199
184
|
}
|
|
200
|
-
.animation(isDragging ? dragSpring : FABConstants.snapAnimation, value: position)
|
|
185
|
+
.animation(didPosition ? (isDragging ? dragSpring : FABConstants.snapAnimation) : nil, value: position)
|
|
201
186
|
}
|
|
202
187
|
.ignoresSafeArea()
|
|
203
188
|
}
|
|
@@ -251,6 +236,31 @@ struct DevMenuFABView: View {
|
|
|
251
236
|
}
|
|
252
237
|
}
|
|
253
238
|
|
|
239
|
+
private func placeInitially(bounds: CGSize, safeArea: EdgeInsets) {
|
|
240
|
+
let initialPos: CGPoint
|
|
241
|
+
if let storedPos = Self.loadStoredPosition() {
|
|
242
|
+
let margin = FABConstants.margin
|
|
243
|
+
let minX = margin / 2
|
|
244
|
+
let maxX = bounds.width - fabSize.width - margin / 2
|
|
245
|
+
let minY = safeArea.top + FABConstants.verticalPadding
|
|
246
|
+
let maxY = bounds.height - fabSize.height - safeArea.bottom - FABConstants.verticalPadding
|
|
247
|
+
|
|
248
|
+
initialPos = CGPoint(
|
|
249
|
+
x: storedPos.x.clamped(to: minX...maxX),
|
|
250
|
+
y: storedPos.y.clamped(to: minY...maxY)
|
|
251
|
+
)
|
|
252
|
+
} else {
|
|
253
|
+
initialPos = defaultPosition(bounds: bounds, safeArea: safeArea)
|
|
254
|
+
}
|
|
255
|
+
position = initialPos
|
|
256
|
+
onFrameChange(CGRect(origin: initialPos, size: fabSize))
|
|
257
|
+
// Enable position animations only after the initial placement so the
|
|
258
|
+
// button appears at its final spot instead of sliding in from (0, 0).
|
|
259
|
+
DispatchQueue.main.async {
|
|
260
|
+
didPosition = true
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
254
264
|
private func defaultPosition(bounds: CGSize, safeArea: EdgeInsets) -> CGPoint {
|
|
255
265
|
CGPoint(
|
|
256
266
|
x: bounds.width - fabSize.width - FABConstants.margin / 2,
|
|
@@ -30,12 +30,13 @@ struct DevMenuAppInfo: View {
|
|
|
30
30
|
label: {
|
|
31
31
|
HStack {
|
|
32
32
|
Text(viewModel.clipboardMessage ?? "Copy system info")
|
|
33
|
-
.foregroundColor(.
|
|
33
|
+
.foregroundColor(.primary)
|
|
34
34
|
Spacer()
|
|
35
|
-
Image(systemName: "
|
|
35
|
+
Image(systemName: "doc.on.clipboard")
|
|
36
36
|
.resizable()
|
|
37
|
+
.scaledToFit()
|
|
37
38
|
.frame(width: 16, height: 16)
|
|
38
|
-
.
|
|
39
|
+
.foregroundColor(.secondary)
|
|
39
40
|
}
|
|
40
41
|
.padding(.vertical)
|
|
41
42
|
.disabled(viewModel.clipboardMessage != nil)
|
|
@@ -33,6 +33,7 @@ struct DevMenuRootView: View {
|
|
|
33
33
|
.id(navigationId)
|
|
34
34
|
.onReceive(DevMenuManager.shared.menuWillShowPublisher) { _ in
|
|
35
35
|
navigationId = UUID()
|
|
36
|
+
viewModel.refresh()
|
|
36
37
|
}
|
|
37
38
|
#else
|
|
38
39
|
NavigationStack {
|
|
@@ -41,6 +42,7 @@ struct DevMenuRootView: View {
|
|
|
41
42
|
.id(navigationId)
|
|
42
43
|
.onReceive(DevMenuManager.shared.menuWillShowPublisher) { _ in
|
|
43
44
|
navigationId = UUID()
|
|
45
|
+
viewModel.refresh()
|
|
44
46
|
}
|
|
45
47
|
#endif
|
|
46
48
|
}
|
|
@@ -32,6 +32,10 @@ class DevMenuViewModel: ObservableObject {
|
|
|
32
32
|
loadFloatingActionButtonState()
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
func refresh() {
|
|
36
|
+
loadData()
|
|
37
|
+
}
|
|
38
|
+
|
|
35
39
|
private func loadAppInfo() {
|
|
36
40
|
let appInfoDict = devMenuManager.getAppInfo()
|
|
37
41
|
|
|
@@ -114,7 +118,7 @@ class DevMenuViewModel: ObservableObject {
|
|
|
114
118
|
func copyToClipboard(_ content: String) {
|
|
115
119
|
#if !os(tvOS) && !os(macOS)
|
|
116
120
|
UIPasteboard.general.string = content
|
|
117
|
-
hostUrlCopiedMessage = "Copied
|
|
121
|
+
hostUrlCopiedMessage = "Copied to clipboard"
|
|
118
122
|
|
|
119
123
|
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
|
120
124
|
self.hostUrlCopiedMessage = nil
|
|
@@ -145,7 +149,7 @@ class DevMenuViewModel: ObservableObject {
|
|
|
145
149
|
let jsonString = jsonData.flatMap { String(data: $0, encoding: .utf8) } ?? "Unable to serialize app info"
|
|
146
150
|
|
|
147
151
|
UIPasteboard.general.string = jsonString
|
|
148
|
-
clipboardMessage = "Copied to clipboard
|
|
152
|
+
clipboardMessage = "Copied to clipboard"
|
|
149
153
|
|
|
150
154
|
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
|
151
155
|
self.clipboardMessage = nil
|
|
@@ -24,7 +24,10 @@ struct HostUrl: View {
|
|
|
24
24
|
Spacer()
|
|
25
25
|
|
|
26
26
|
Image(systemName: "doc.on.clipboard")
|
|
27
|
-
.
|
|
27
|
+
.resizable()
|
|
28
|
+
.scaledToFit()
|
|
29
|
+
.frame(width: 16, height: 16)
|
|
30
|
+
.foregroundColor(.secondary)
|
|
28
31
|
}
|
|
29
32
|
.padding()
|
|
30
33
|
.background(Color.expoSecondarySystemBackground)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-dev-menu",
|
|
3
|
-
"version": "57.0.
|
|
3
|
+
"version": "57.0.1",
|
|
4
4
|
"description": "Expo/React Native module with the developer menu.",
|
|
5
5
|
"main": "build/DevMenu.js",
|
|
6
6
|
"types": "build/DevMenu.d.ts",
|
|
@@ -32,15 +32,15 @@
|
|
|
32
32
|
"@types/node": "^22.14.0",
|
|
33
33
|
"react": "19.2.3",
|
|
34
34
|
"react-native": "0.86.0",
|
|
35
|
-
"babel-preset-expo": "57.0.0",
|
|
36
35
|
"expo": "57.0.0-preview.0",
|
|
36
|
+
"babel-preset-expo": "57.0.0",
|
|
37
37
|
"expo-module-scripts": "56.0.3"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"expo": "*",
|
|
41
41
|
"react-native": "*"
|
|
42
42
|
},
|
|
43
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "edfbc4c08a791e8dc73975b414261cb1da32ead9",
|
|
44
44
|
"scripts": {
|
|
45
45
|
"build": "expo-module build",
|
|
46
46
|
"clean": "expo-module clean",
|