From 05b620b5b974143e9fd4f3afe8f5a27ca0feacf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Kwa=C5=9Bniewski?= Date: Mon, 24 Jun 2024 12:10:23 +0200 Subject: [PATCH] fix: allow to manually move dev menu to avoid conflicts (#150) --- .../SwiftExtensions/RCTMainWindow.swift | 44 +++--------------- .../RCTRootViewRepresentable.swift | 45 ++++++++++++++++++- .../Libraries/SwiftExtensions/RCTWindow.swift | 2 +- 3 files changed, 50 insertions(+), 41 deletions(-) diff --git a/packages/react-native/Libraries/SwiftExtensions/RCTMainWindow.swift b/packages/react-native/Libraries/SwiftExtensions/RCTMainWindow.swift index be7d25cdae98b4..85652c59463708 100644 --- a/packages/react-native/Libraries/SwiftExtensions/RCTMainWindow.swift +++ b/packages/react-native/Libraries/SwiftExtensions/RCTMainWindow.swift @@ -1,5 +1,4 @@ import SwiftUI -import React /** This SwiftUI struct returns main React Native scene. It should be used only once as it conains setup code. @@ -22,11 +21,11 @@ public struct RCTMainWindow: Scene { var moduleName: String var initialProps: RCTRootViewRepresentable.InitialPropsType var onOpenURLCallback: ((URL) -> ())? - var devMenuPlacement: ToolbarPlacement = .bottomOrnament + var devMenuSceneAnchor: UnitPoint? var contentView: AnyView? var rootView: RCTRootViewRepresentable { - RCTRootViewRepresentable(moduleName: moduleName, initialProps: initialProps) + RCTRootViewRepresentable(moduleName: moduleName, initialProps: initialProps, devMenuSceneAnchor: devMenuSceneAnchor) } /// Creates new RCTMainWindowWindow. @@ -38,11 +37,11 @@ public struct RCTMainWindow: Scene { public init( moduleName: String, initialProps: RCTRootViewRepresentable.InitialPropsType = nil, - devMenuPlacement: ToolbarPlacement = .bottomOrnament + devMenuSceneAnchor: UnitPoint? = .bottom ) { self.moduleName = moduleName self.initialProps = initialProps - self.devMenuPlacement = devMenuPlacement + self.devMenuSceneAnchor = devMenuSceneAnchor self.contentView = AnyView(rootView) } @@ -56,12 +55,12 @@ public struct RCTMainWindow: Scene { public init( moduleName: String, initialProps: RCTRootViewRepresentable.InitialPropsType = nil, - devMenuPlacement: ToolbarPlacement = .bottomOrnament, + devMenuSceneAnchor: UnitPoint? = .bottom, @ViewBuilder contentView: @escaping (_ view: RCTRootViewRepresentable) -> Content ) { self.moduleName = moduleName self.initialProps = initialProps - self.devMenuPlacement = devMenuPlacement + self.devMenuSceneAnchor = devMenuSceneAnchor self.contentView = AnyView(contentView(rootView)) } @@ -72,11 +71,6 @@ public struct RCTMainWindow: Scene { .onOpenURL(perform: { url in onOpenURLCallback?(url) }) -#if DEBUG - .toolbar { - DevMenuView(placement: .bottomOrnament) - } -#endif } } } @@ -139,29 +133,3 @@ public struct WindowHandlingModifier: ViewModifier { } } -/** - Toolbar which displays additional controls to easily open dev menu and trigger reload command. - */ -struct DevMenuView: ToolbarContent { - let placement: ToolbarItemPlacement - - var body: some ToolbarContent { - ToolbarItem(placement: placement) { - Button(action: { - RCTTriggerReloadCommandListeners("User Reload") - }, label: { - Image(systemName: "arrow.clockwise") - }) - } - ToolbarItem(placement: placement) { - Button(action: { - NotificationCenter.default.post( - Notification(name: Notification.Name("RCTShowDevMenuNotification"), object: nil) - ) - }, - label: { - Image(systemName: "filemenu.and.selection") - }) - } - } -} diff --git a/packages/react-native/Libraries/SwiftExtensions/RCTRootViewRepresentable.swift b/packages/react-native/Libraries/SwiftExtensions/RCTRootViewRepresentable.swift index 8a839541ebb8ea..cb774b8327ca9b 100644 --- a/packages/react-native/Libraries/SwiftExtensions/RCTRootViewRepresentable.swift +++ b/packages/react-native/Libraries/SwiftExtensions/RCTRootViewRepresentable.swift @@ -1,4 +1,5 @@ import SwiftUI +import React /** SwiftUI view enclosing `RCTReactViewController`. Its main purpose is to display React Native views inside of SwiftUI lifecycle. @@ -16,17 +17,57 @@ public struct RCTRootViewRepresentable: UIViewControllerRepresentable { var moduleName: String var initialProps: InitialPropsType + var devMenuSceneAnchor: UnitPoint? - public init(moduleName: String, initialProps: InitialPropsType = nil) { + public init( + moduleName: String, + initialProps: InitialPropsType = nil, + devMenuSceneAnchor: UnitPoint? = .bottom + ) { self.moduleName = moduleName self.initialProps = initialProps + self.devMenuSceneAnchor = devMenuSceneAnchor } public func makeUIViewController(context: Context) -> RCTReactViewController { - RCTReactViewController(moduleName: moduleName, initProps: initialProps) + let viewController = RCTReactViewController(moduleName: moduleName, initProps: initialProps) +#if DEBUG + if let devMenuSceneAnchor { + let ornament = UIHostingOrnament(sceneAnchor: devMenuSceneAnchor) { + DevMenuView() + } + viewController.ornaments.append(ornament) + } +#endif + return viewController } public func updateUIViewController(_ uiViewController: RCTReactViewController, context: Context) { uiViewController.updateProps(initialProps) } } + +/** + Toolbar which displays additional controls to easily open dev menu and trigger reload command. + */ +struct DevMenuView: View { + var body: some View { + HStack { + Button(action: { + RCTTriggerReloadCommandListeners("User Reload") + }, label: { + Image(systemName: "arrow.clockwise") + }) + Button(action: { + NotificationCenter.default.post( + Notification(name: Notification.Name("RCTShowDevMenuNotification"), object: nil) + ) + }, + label: { + Image(systemName: "filemenu.and.selection") + }) + } + .padding() + .glassBackgroundEffect() + } +} diff --git a/packages/react-native/Libraries/SwiftExtensions/RCTWindow.swift b/packages/react-native/Libraries/SwiftExtensions/RCTWindow.swift index fe678107d0ec00..d2bc884953b57a 100644 --- a/packages/react-native/Libraries/SwiftExtensions/RCTWindow.swift +++ b/packages/react-native/Libraries/SwiftExtensions/RCTWindow.swift @@ -16,7 +16,7 @@ public struct RCTWindow : Scene { var contentView: AnyView? func getRootView(sceneData: RCTSceneData?) -> RCTRootViewRepresentable { - return RCTRootViewRepresentable(moduleName: moduleName, initialProps: sceneData?.props ?? [:]) + return RCTRootViewRepresentable(moduleName: moduleName, initialProps: sceneData?.props ?? [:], devMenuSceneAnchor: nil) } public var body: some Scene {