Add `DefaultApp` type to simplify `DOMRenderer.init` (#217)
This means that the `View` initializer of `DOMRenderer` now can delegate to the `App` initializer by creating a wrapping `DefaultApp`. It would simplify https://github.com/swiftwasm/Tokamak/pull/136 for me, where I no longer need to implement color scheme observation for these two different codepaths separately.
This commit is contained in:
parent
8041732dc9
commit
7c6b1812ae
|
@ -29,8 +29,8 @@ public protocol App: _TitledApp {
|
|||
var body: Body { get }
|
||||
|
||||
/// Implemented by the renderer to mount the `App`
|
||||
static func _launch(_ app: Self,
|
||||
_ rootEnvironment: EnvironmentValues)
|
||||
static func _launch(_ app: Self, _ rootEnvironment: EnvironmentValues)
|
||||
|
||||
/// Implemented by the renderer to update the `App` on `ScenePhase` changes
|
||||
var _phasePublisher: CurrentValueSubject<ScenePhase, Never> { get }
|
||||
|
||||
|
|
|
@ -58,8 +58,8 @@ public final class StackReconciler<R: Renderer> {
|
|||
rootElement.mount(with: self)
|
||||
if let mountedApp = rootElement as? MountedApp<R> {
|
||||
app._phasePublisher.sink { [weak self] phase in
|
||||
if mountedApp.environmentValues[keyPath: \.scenePhase] != phase {
|
||||
mountedApp.environmentValues[keyPath: \.scenePhase] = phase
|
||||
if mountedApp.environmentValues.scenePhase != phase {
|
||||
mountedApp.environmentValues.scenePhase = phase
|
||||
self?.queueUpdate(for: mountedApp)
|
||||
}
|
||||
}.store(in: &mountedApp.subscriptions)
|
||||
|
|
|
@ -23,7 +23,6 @@ private enum ScenePhaseObserver {
|
|||
static var publisher = CurrentValueSubject<ScenePhase, Never>(.active)
|
||||
|
||||
static func observe() {
|
||||
let document = JSObjectRef.global.document.object!
|
||||
_ = document.addEventListener!("visibilitychange", JSClosure { _ in
|
||||
let visibilityState = document.visibilityState.string
|
||||
if visibilityState == "visible" {
|
||||
|
@ -44,12 +43,11 @@ extension App {
|
|||
/// The body is styled with `margin: 0;` to match the `SwiftUI` layout
|
||||
/// system as closely as possible
|
||||
///
|
||||
public static func _launch(_ app: Self,
|
||||
_ rootEnvironment: EnvironmentValues) {
|
||||
let document = JSObjectRef.global.document.object!
|
||||
let body = document.body.object!
|
||||
let head = document.head.object!
|
||||
body.style = "margin: 0;"
|
||||
public static func _launch(_ app: Self, _ rootEnvironment: EnvironmentValues) {
|
||||
let body = TokamakDOM.body
|
||||
if body.style == .undefined {
|
||||
body.style = "margin: 0;"
|
||||
}
|
||||
let rootStyle = document.createElement!("style").object!
|
||||
rootStyle.id = "_tokamak-app-style"
|
||||
rootStyle.innerHTML = .string(tokamakStyles)
|
||||
|
@ -74,3 +72,13 @@ extension App {
|
|||
ScenePhaseObserver.publisher
|
||||
}
|
||||
}
|
||||
|
||||
struct DefaultApp<V: View>: App {
|
||||
var content: V?
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
content
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ extension EnvironmentValues {
|
|||
static var defaultEnvironment: Self {
|
||||
var environment = EnvironmentValues()
|
||||
environment[_ToggleStyleKey] = _AnyToggleStyle(DefaultToggleStyle())
|
||||
environment[keyPath: \._defaultAppStorage] = LocalStorage.standard
|
||||
environment._defaultAppStorage = LocalStorage.standard
|
||||
_DefaultSceneStorageProvider.default = SessionStorage.standard
|
||||
|
||||
return environment
|
||||
|
@ -55,6 +55,7 @@ private extension AnyView {
|
|||
|
||||
let log = JSObjectRef.global.console.object!.log.function!
|
||||
let document = JSObjectRef.global.document.object!
|
||||
let body = document.body.object!
|
||||
let head = document.head.object!
|
||||
|
||||
let timeoutScheduler = { (closure: @escaping () -> ()) in
|
||||
|
@ -77,28 +78,15 @@ public final class DOMRenderer: Renderer {
|
|||
|
||||
private let rootRef: JSObjectRef
|
||||
|
||||
public init<V: View>(
|
||||
public convenience init<V: View>(
|
||||
_ view: V,
|
||||
_ ref: JSObjectRef,
|
||||
_ rootEnvironment: EnvironmentValues? = nil
|
||||
) {
|
||||
rootRef = ref
|
||||
appendRootStyle(ref)
|
||||
|
||||
reconciler = StackReconciler(
|
||||
view: view,
|
||||
target: DOMNode(view, ref),
|
||||
environment: .defaultEnvironment,
|
||||
renderer: self,
|
||||
scheduler: timeoutScheduler
|
||||
)
|
||||
self.init(DefaultApp(content: view), ref, rootEnvironment)
|
||||
}
|
||||
|
||||
init<A: App>(
|
||||
_ app: A,
|
||||
_ ref: JSObjectRef,
|
||||
_ rootEnvironment: EnvironmentValues? = nil
|
||||
) {
|
||||
init<A: App>(_ app: A, _ ref: JSObjectRef, _ rootEnvironment: EnvironmentValues? = nil) {
|
||||
rootRef = ref
|
||||
appendRootStyle(ref)
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ extension AnyHTML {
|
|||
// then use the standard lib to get the difference?
|
||||
|
||||
for (attribute, value) in attributes {
|
||||
_ = dom.ref[dynamicMember: attribute] = JSValue(stringLiteral: value)
|
||||
_ = dom.ref[dynamicMember: attribute] = .string(value)
|
||||
}
|
||||
|
||||
dom.reinstall(listeners)
|
||||
|
|
Loading…
Reference in New Issue