Skip to content

Commit

Permalink
feat: add support for ornaments
Browse files Browse the repository at this point in the history
  • Loading branch information
okwasniewski committed Jun 7, 2024
1 parent 8013270 commit 14a6f5b
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import SwiftUI
import React

/**
This SwiftUI struct returns main React Native scene. It should be used only once as it conains setup code.
Expand All @@ -7,11 +8,11 @@ import SwiftUI
```swift
@main
struct YourApp: App {
@UIApplicationDelegateAdaptor var delegate: AppDelegate
var body: some Scene {
RCTMainWindow(moduleName: "YourApp")
}
@UIApplicationDelegateAdaptor var delegate: AppDelegate

var body: some Scene {
RCTMainWindow(moduleName: "YourApp")
}
}
```

Expand All @@ -21,25 +22,54 @@ public struct RCTMainWindow: Scene {
var moduleName: String
var initialProps: RCTRootViewRepresentable.InitialPropsType
var onOpenURLCallback: ((URL) -> ())?
var devMenuPlacement: ToolbarPlacement = .bottomOrnament
var contentView: AnyView?

var rootView: RCTRootViewRepresentable {
RCTRootViewRepresentable(moduleName: moduleName, initialProps: initialProps)
}

public init(
moduleName: String,
initialProps: RCTRootViewRepresentable.InitialPropsType = nil,
devMenuPlacement: ToolbarPlacement = .bottomOrnament
) {
self.moduleName = moduleName
self.initialProps = initialProps
self.devMenuPlacement = devMenuPlacement
self.contentView = AnyView(rootView)
}

public init(moduleName: String, initialProps: RCTRootViewRepresentable.InitialPropsType = nil) {
public init<Content: View>(
moduleName: String,
initialProps: RCTRootViewRepresentable.InitialPropsType = nil,
devMenuPlacement: ToolbarPlacement = .bottomOrnament,
@ViewBuilder contentView: @escaping (_ view: RCTRootViewRepresentable) -> Content
) {
self.moduleName = moduleName
self.initialProps = initialProps
self.devMenuPlacement = devMenuPlacement
self.contentView = AnyView(contentView(rootView))
}

public var body: some Scene {
WindowGroup {
RCTRootViewRepresentable(moduleName: moduleName, initialProps: initialProps)
contentView
.modifier(WindowHandlingModifier())
.onOpenURL(perform: { url in
onOpenURLCallback?(url)
})
#if DEBUG
.toolbar {
DevMenuView(placement: .bottomOrnament)
}
#endif
}
}
}

extension RCTMainWindow {
public func onOpenURL(perform action: @escaping (URL) -> ()) -> some Scene {
public func onOpenURL(perform action: @escaping (URL) -> ()) -> Self {
var scene = self
scene.onOpenURLCallback = action
return scene
Expand Down Expand Up @@ -95,3 +125,27 @@ public struct WindowHandlingModifier: ViewModifier {
}
}
}

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")
})
}
}
}
19 changes: 19 additions & 0 deletions packages/react-native/React/Base/RCTUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,7 @@ BOOL RCTRunningInAppExtension(void)
if (scene.session.role == UISceneSessionRoleImmersiveSpaceApplication) {
continue;
}

#endif

if (scene.activationState == UISceneActivationStateForegroundActive) {
Expand All @@ -608,6 +609,24 @@ BOOL RCTRunningInAppExtension(void)
UIScene *sceneToUse = foregroundActiveScene ? foregroundActiveScene : foregroundInactiveScene;
UIWindowScene *windowScene = (UIWindowScene *)sceneToUse;

#if TARGET_OS_VISION
// Ornaments are supported only on visionOS.
// When clicking on an ornament it becomes the keyWindow.
// Presenting a RN modal from ornament leads to a crash.
UIWindow* keyWindow = windowScene.keyWindow;
BOOL isOrnament = [keyWindow.debugDescription containsString:@"Ornament"];
if (isOrnament) {
for (UIWindow *window in windowScene.windows) {
BOOL isOrnament = [window.debugDescription containsString:@"Ornament"];
if (window != keyWindow && !isOrnament) {
return window;
}
}
}

return keyWindow;
#endif

if (@available(iOS 15.0, *)) {
return windowScene.keyWindow;
}
Expand Down

0 comments on commit 14a6f5b

Please sign in to comment.