Skip to content

Commit 0d50fe3

Browse files
committed
feat: add support for ornaments
1 parent 8013270 commit 0d50fe3

File tree

2 files changed

+73
-7
lines changed

2 files changed

+73
-7
lines changed

packages/react-native/Libraries/SwiftExtensions/RCTMainWindow.swift

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import SwiftUI
2+
import React
23

34
/**
45
This SwiftUI struct returns main React Native scene. It should be used only once as it conains setup code.
@@ -7,11 +8,11 @@ import SwiftUI
78
```swift
89
@main
910
struct YourApp: App {
10-
@UIApplicationDelegateAdaptor var delegate: AppDelegate
11-
12-
var body: some Scene {
13-
RCTMainWindow(moduleName: "YourApp")
14-
}
11+
@UIApplicationDelegateAdaptor var delegate: AppDelegate
12+
13+
var body: some Scene {
14+
RCTMainWindow(moduleName: "YourApp")
15+
}
1516
}
1617
```
1718

@@ -21,25 +22,47 @@ public struct RCTMainWindow: Scene {
2122
var moduleName: String
2223
var initialProps: RCTRootViewRepresentable.InitialPropsType
2324
var onOpenURLCallback: ((URL) -> ())?
25+
var contentView: AnyView?
2426

27+
var rootView: RCTRootViewRepresentable {
28+
RCTRootViewRepresentable(moduleName: moduleName, initialProps: initialProps)
29+
}
30+
2531
public init(moduleName: String, initialProps: RCTRootViewRepresentable.InitialPropsType = nil) {
2632
self.moduleName = moduleName
2733
self.initialProps = initialProps
34+
self.contentView = AnyView(rootView)
35+
}
36+
37+
public init<Content: View>(
38+
moduleName: String,
39+
initialProps: RCTRootViewRepresentable.InitialPropsType = nil,
40+
devMenuPlacement: ToolbarPlacement = .bottomBar,
41+
@ViewBuilder contentView: @escaping (_ view: RCTRootViewRepresentable) -> Content
42+
) {
43+
self.moduleName = moduleName
44+
self.initialProps = initialProps
45+
self.contentView = AnyView(contentView(rootView))
2846
}
2947

3048
public var body: some Scene {
3149
WindowGroup {
32-
RCTRootViewRepresentable(moduleName: moduleName, initialProps: initialProps)
50+
contentView
3351
.modifier(WindowHandlingModifier())
3452
.onOpenURL(perform: { url in
3553
onOpenURLCallback?(url)
3654
})
55+
#if DEBUG
56+
.toolbar {
57+
DevMenuView(placement: .bottomOrnament)
58+
}
59+
#endif
3760
}
3861
}
3962
}
4063

4164
extension RCTMainWindow {
42-
public func onOpenURL(perform action: @escaping (URL) -> ()) -> some Scene {
65+
public func onOpenURL(perform action: @escaping (URL) -> ()) -> Self {
4366
var scene = self
4467
scene.onOpenURLCallback = action
4568
return scene
@@ -95,3 +118,27 @@ public struct WindowHandlingModifier: ViewModifier {
95118
}
96119
}
97120
}
121+
122+
struct DevMenuView: ToolbarContent {
123+
let placement: ToolbarItemPlacement
124+
125+
var body: some ToolbarContent {
126+
ToolbarItem(placement: placement) {
127+
Button(action: {
128+
RCTTriggerReloadCommandListeners("User Reload")
129+
}, label: {
130+
Image(systemName: "arrow.clockwise")
131+
})
132+
}
133+
ToolbarItem(placement: placement) {
134+
Button(action: {
135+
NotificationCenter.default.post(
136+
Notification(name: Notification.Name("RCTShowDevMenuNotification"), object: nil)
137+
)
138+
},
139+
label: {
140+
Image(systemName: "filemenu.and.selection")
141+
})
142+
}
143+
}
144+
}

packages/react-native/React/Base/RCTUtils.m

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,7 @@ BOOL RCTRunningInAppExtension(void)
592592
if (scene.session.role == UISceneSessionRoleImmersiveSpaceApplication) {
593593
continue;
594594
}
595+
595596
#endif
596597

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

612+
#if TARGET_OS_VISION
613+
// Ornaments are supported only on visionOS.
614+
// When clicking on an ornament it becomes the keyWindow.
615+
// Presenting a RN modal from ornament leads to a crash.
616+
UIWindow* keyWindow = windowScene.keyWindow;
617+
BOOL isOrnament = [keyWindow.debugDescription containsString:@"Ornament"];
618+
if (isOrnament) {
619+
for (UIWindow *window in windowScene.windows) {
620+
BOOL isOrnament = [window.debugDescription containsString:@"Ornament"];
621+
if (window != keyWindow && !isOrnament) {
622+
return window;
623+
}
624+
}
625+
}
626+
627+
return keyWindow;
628+
#endif
629+
611630
if (@available(iOS 15.0, *)) {
612631
return windowScene.keyWindow;
613632
}

0 commit comments

Comments
 (0)