@@ -15,20 +15,121 @@ import SwiftUI
15
15
}
16
16
```
17
17
18
- Note: If you want to create additional windows in your app, create a new `WindowGroup {}` and pass it a `RCTRootViewRepresentable `.
19
- */
18
+ Note: If you want to create additional windows in your app, use `RCTWindow() `.
19
+ */
20
20
public struct RCTMainWindow : Scene {
21
21
var moduleName : String
22
22
var initialProps : RCTRootViewRepresentable . InitialPropsType
23
+ var onOpenURLCallback : ( ( URL ) -> ( ) ) ?
24
+ var devMenuSceneAnchor : UnitPoint ?
25
+ var contentView : AnyView ?
23
26
24
- public init ( moduleName: String , initialProps: RCTRootViewRepresentable . InitialPropsType = nil ) {
27
+ var rootView : RCTRootViewRepresentable {
28
+ RCTRootViewRepresentable ( moduleName: moduleName, initialProps: initialProps, devMenuSceneAnchor: devMenuSceneAnchor)
29
+ }
30
+
31
+ /// Creates new RCTMainWindowWindow.
32
+ ///
33
+ /// - Parameters:
34
+ /// - moduleName: Name of the module registered using `AppRegistry.registerComponent()`
35
+ /// - initialProps: Initial properties for this view.
36
+ /// - devMenuPlacement: Placement of the additional controls for triggering reload command and dev menu trigger.
37
+ public init (
38
+ moduleName: String ,
39
+ initialProps: RCTRootViewRepresentable . InitialPropsType = nil ,
40
+ devMenuSceneAnchor: UnitPoint ? = . bottom
41
+ ) {
25
42
self . moduleName = moduleName
26
43
self . initialProps = initialProps
44
+ self . devMenuSceneAnchor = devMenuSceneAnchor
45
+ self . contentView = AnyView ( rootView)
46
+ }
47
+
48
+ /// Creates new RCTMainWindowWindow.
49
+ ///
50
+ /// - Parameters:
51
+ /// - moduleName: Name of the module registered using `AppRegistry.registerComponent()`
52
+ /// - initialProps: Initial properties for this view.
53
+ /// - devMenuPlacement: Placement of the additional controls for triggering reload command and dev menu trigger.
54
+ /// - contentView: Closure which accepts rootView, allows to apply additional modifiers to React Native rootView.
55
+ public init < Content: View > (
56
+ moduleName: String ,
57
+ initialProps: RCTRootViewRepresentable . InitialPropsType = nil ,
58
+ devMenuSceneAnchor: UnitPoint ? = . bottom,
59
+ @ViewBuilder contentView: @escaping ( _ view: RCTRootViewRepresentable ) -> Content
60
+ ) {
61
+ self . moduleName = moduleName
62
+ self . initialProps = initialProps
63
+ self . devMenuSceneAnchor = devMenuSceneAnchor
64
+ self . contentView = AnyView ( contentView ( rootView) )
27
65
}
28
66
29
67
public var body : some Scene {
30
68
WindowGroup {
31
- RCTRootViewRepresentable ( moduleName: moduleName, initialProps: initialProps)
69
+ contentView
70
+ . modifier ( WindowHandlingModifier ( ) )
71
+ . onOpenURL ( perform: { url in
72
+ onOpenURLCallback ? ( url)
73
+ } )
74
+ }
75
+ }
76
+ }
77
+
78
+ extension RCTMainWindow {
79
+ public func onOpenURL( perform action: @escaping ( URL ) -> ( ) ) -> Self {
80
+ var scene = self
81
+ scene. onOpenURLCallback = action
82
+ return scene
83
+ }
84
+ }
85
+
86
+ /**
87
+ Handles data sharing between React Native and SwiftUI views.
88
+ */
89
+ public struct WindowHandlingModifier : ViewModifier {
90
+ typealias UserInfoType = Dictionary < String , AnyHashable >
91
+
92
+ @Environment ( \. reactContext) private var reactContext
93
+ @Environment ( \. openWindow) private var openWindow
94
+ @Environment ( \. dismissWindow) private var dismissWindow
95
+ @Environment ( \. supportsMultipleWindows) private var supportsMultipleWindows
96
+
97
+ public init ( ) { }
98
+
99
+ public func body( content: Content ) -> some View {
100
+ // Attach listeners only if app supports multiple windows
101
+ if supportsMultipleWindows {
102
+ content
103
+ . onReceive ( NotificationCenter . default. publisher ( for: NSNotification . Name ( " RCTOpenWindow " ) ) ) { data in
104
+ guard let id = data. userInfo ? [ " id " ] as? String else { return }
105
+ reactContext. scenes. updateValue ( RCTSceneData ( id: id, props: data. userInfo ? [ " userInfo " ] as? UserInfoType ) , forKey: id)
106
+ openWindow ( id: id)
107
+ }
108
+ . onReceive ( NotificationCenter . default. publisher ( for: NSNotification . Name ( " RCTUpdateWindow " ) ) ) { data in
109
+ guard
110
+ let id = data. userInfo ? [ " id " ] as? String ,
111
+ let userInfo = data. userInfo ? [ " userInfo " ] as? UserInfoType else { return }
112
+ reactContext. scenes [ id] ? . props = userInfo
113
+ }
114
+ . onReceive ( NotificationCenter . default. publisher ( for: NSNotification . Name ( " RCTDismissWindow " ) ) ) { data in
115
+ guard let id = data. userInfo ? [ " id " ] as? String else { return }
116
+ dismissWindow ( id: id)
117
+ reactContext. scenes. removeValue ( forKey: id)
118
+ }
119
+ . onReceive ( NotificationCenter . default. publisher ( for: NSNotification . Name ( " RCTOpenImmersiveSpace " ) ) ) { data in
120
+ guard let id = data. userInfo ? [ " id " ] as? String else { return }
121
+ reactContext. scenes. updateValue (
122
+ RCTSceneData ( id: id, props: data. userInfo ? [ " userInfo " ] as? UserInfoType ) ,
123
+ forKey: id
124
+ )
125
+ }
126
+ . onReceive ( NotificationCenter . default. publisher ( for: NSNotification . Name ( " RCTDismissImmersiveSpace " ) ) ) { data in
127
+ guard let id = data. userInfo ? [ " id " ] as? String else { return }
128
+ reactContext. scenes. removeValue ( forKey: id)
129
+ }
130
+ } else {
131
+ content
32
132
}
33
133
}
34
134
}
135
+
0 commit comments