forked from facebook/react-native
-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add multi-window support (#117)
* feat: add multi-window support * feat: introduce WindowManager fix: RCTReactViewController properly check props to update fix: use clearColor instead of systemBackgroundColor for visionOS (#125)
- Loading branch information
1 parent
0599a11
commit 2f8e8b6
Showing
32 changed files
with
849 additions
and
163 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
packages/react-native/Libraries/SwiftExtensions/RCTReactContext.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import SwiftUI | ||
import Observation | ||
|
||
@Observable | ||
public class RCTSceneData: Identifiable { | ||
public var id: String | ||
public var props: Dictionary<String, AnyHashable>? | ||
|
||
init(id: String, props: Dictionary<String, AnyHashable>?) { | ||
self.id = id | ||
self.props = props | ||
} | ||
} | ||
|
||
extension RCTSceneData: Equatable { | ||
public static func == (lhs: RCTSceneData, rhs: RCTSceneData) -> Bool { | ||
lhs.id == rhs.id && NSDictionary(dictionary: lhs.props ?? [:]).isEqual(to: rhs.props ?? [:]) | ||
} | ||
} | ||
|
||
@Observable | ||
public class RCTReactContext { | ||
public var scenes: Dictionary<String, RCTSceneData> = [:] | ||
|
||
public func getSceneData(id: String) -> RCTSceneData? { | ||
return scenes[id] | ||
} | ||
} | ||
|
||
extension RCTReactContext: Equatable { | ||
public static func == (lhs: RCTReactContext, rhs: RCTReactContext) -> Bool { | ||
NSDictionary(dictionary: lhs.scenes).isEqual(to: rhs.scenes) | ||
} | ||
} | ||
|
||
public extension EnvironmentValues { | ||
var reactContext: RCTReactContext { | ||
get { self[RCTSceneContextKey.self] } | ||
set { self[RCTSceneContextKey.self] = newValue } | ||
} | ||
} | ||
|
||
private struct RCTSceneContextKey: EnvironmentKey { | ||
static var defaultValue: RCTReactContext = RCTReactContext() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
packages/react-native/Libraries/SwiftExtensions/RCTWindow.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import SwiftUI | ||
import React | ||
|
||
/** | ||
`RCTWindow` is a SwiftUI struct that returns additional scenes. | ||
|
||
Example usage: | ||
``` | ||
RCTWindow(id: "SecondWindow", sceneData: reactContext.getSceneData(id: "SecondWindow")) | ||
``` | ||
*/ | ||
public struct RCTWindow : Scene { | ||
var id: String | ||
var sceneData: RCTSceneData? | ||
var moduleName: String | ||
|
||
public init(id: String, moduleName: String, sceneData: RCTSceneData?) { | ||
self.id = id | ||
self.moduleName = moduleName | ||
self.sceneData = sceneData | ||
} | ||
|
||
public var body: some Scene { | ||
WindowGroup(id: id) { | ||
Group { | ||
if let sceneData { | ||
RCTRootViewRepresentable(moduleName: moduleName, initialProps: sceneData.props) | ||
} | ||
} | ||
.onAppear { | ||
if sceneData == nil { | ||
RCTFatal(RCTErrorWithMessage("Passed scene data is nil, make sure to pass sceneContext to RCTWindow() in App.swift")) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
extension RCTWindow { | ||
public init(id: String, sceneData: RCTSceneData?) { | ||
self.id = id | ||
self.moduleName = id | ||
self.sceneData = sceneData | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
packages/react-native/Libraries/WindowManager/NativeWindowManager.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/** | ||
* @flow strict | ||
* @format | ||
*/ | ||
|
||
export * from '../../src/private/specs/visionos_modules/NativeWindowManager'; | ||
import NativeWindowManager from '../../src/private/specs/visionos_modules/NativeWindowManager'; | ||
export default NativeWindowManager; |
6 changes: 6 additions & 0 deletions
6
packages/react-native/Libraries/WindowManager/RCTWindowManager.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#import <Foundation/Foundation.h> | ||
#import <React/RCTBridgeModule.h> | ||
|
||
@interface RCTWindowManager : NSObject <RCTBridgeModule> | ||
|
||
@end |
90 changes: 90 additions & 0 deletions
90
packages/react-native/Libraries/WindowManager/RCTWindowManager.mm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
#import <React/RCTWindowManager.h> | ||
|
||
#import <FBReactNativeSpec_visionOS/FBReactNativeSpec_visionOS.h> | ||
|
||
#import <React/RCTBridge.h> | ||
#import <React/RCTConvert.h> | ||
#import <React/RCTUtils.h> | ||
|
||
// Events | ||
static NSString *const RCTOpenWindow = @"RCTOpenWindow"; | ||
static NSString *const RCTDismissWindow = @"RCTDismissWindow"; | ||
static NSString *const RCTUpdateWindow = @"RCTUpdateWindow"; | ||
|
||
@interface RCTWindowManager () <NativeWindowManagerSpec> | ||
@end | ||
|
||
@implementation RCTWindowManager | ||
|
||
RCT_EXPORT_MODULE(WindowManager) | ||
|
||
RCT_EXPORT_METHOD(openWindow | ||
: (NSString *)windowId userInfo | ||
: (NSDictionary *)userInfo resolve | ||
: (RCTPromiseResolveBlock)resolve reject | ||
: (RCTPromiseRejectBlock)reject) | ||
{ | ||
RCTExecuteOnMainQueue(^{ | ||
if (!RCTSharedApplication().supportsMultipleScenes) { | ||
reject(@"ERROR", @"Multiple scenes not supported", nil); | ||
} | ||
NSMutableDictionary *userInfoDict = [[NSMutableDictionary alloc] init]; | ||
[userInfoDict setValue:windowId forKey:@"id"]; | ||
if (userInfo != nil) { | ||
[userInfoDict setValue:userInfo forKey:@"userInfo"]; | ||
} | ||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTOpenWindow object:self userInfo:userInfoDict]; | ||
resolve(nil); | ||
}); | ||
} | ||
|
||
RCT_EXPORT_METHOD(closeWindow | ||
: (NSString *)windowId resolve | ||
: (RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) | ||
{ | ||
RCTExecuteOnMainQueue(^{ | ||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTDismissWindow object:self userInfo:@{@"id": windowId}]; | ||
resolve(nil); | ||
}); | ||
} | ||
|
||
RCT_EXPORT_METHOD(updateWindow | ||
: (NSString *)windowId userInfo | ||
: (NSDictionary *)userInfo resolve | ||
: (RCTPromiseResolveBlock)resolve reject | ||
: (RCTPromiseRejectBlock)reject) | ||
{ | ||
RCTExecuteOnMainQueue(^{ | ||
if (!RCTSharedApplication().supportsMultipleScenes) { | ||
reject(@"ERROR", @"Multiple scenes not supported", nil); | ||
} | ||
NSMutableDictionary *userInfoDict = [[NSMutableDictionary alloc] init]; | ||
[userInfoDict setValue:windowId forKey:@"id"]; | ||
if (userInfo != nil) { | ||
[userInfoDict setValue:userInfo forKey:@"userInfo"]; | ||
} | ||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTUpdateWindow object:self userInfo:userInfoDict]; | ||
resolve(nil); | ||
}); | ||
} | ||
|
||
- (facebook::react::ModuleConstants<JS::NativeWindowManager::Constants::Builder>)constantsToExport { | ||
return [self getConstants]; | ||
} | ||
|
||
- (facebook::react::ModuleConstants<JS::NativeWindowManager::Constants>)getConstants { | ||
__block facebook::react::ModuleConstants<JS::NativeWindowManager::Constants> constants; | ||
RCTUnsafeExecuteOnMainQueueSync(^{ | ||
constants = facebook::react::typedConstants<JS::NativeWindowManager::Constants>({ | ||
.supportsMultipleScenes = RCTSharedApplication().supportsMultipleScenes | ||
}); | ||
}); | ||
|
||
return constants; | ||
} | ||
|
||
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params { | ||
return std::make_shared<facebook::react::NativeWindowManagerSpecJSI>(params); | ||
} | ||
|
||
@end |
16 changes: 16 additions & 0 deletions
16
packages/react-native/Libraries/WindowManager/WindowManager.d.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
export interface WindowStatic { | ||
id: String; | ||
open (props?: Object): Promise<void>; | ||
update (props: Object): Promise<void>; | ||
close (): Promise<void>; | ||
} | ||
|
||
export interface WindowManagerStatic { | ||
getWindow(id: String): Window; | ||
supportsMultipleScenes: boolean; | ||
} | ||
|
||
export const WindowManager: WindowManagerStatic; | ||
export type WindowManager = WindowManagerStatic; | ||
export const Window: WindowStatic; | ||
export type Window = WindowStatic; |
Oops, something went wrong.