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:
Max Desiatov 2020-07-29 09:26:08 +01:00 committed by GitHub
parent 8041732dc9
commit 7c6b1812ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 25 additions and 29 deletions

View File

@ -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 }

View File

@ -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)

View File

@ -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
}
}
}

View File

@ -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)

View File

@ -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)