Add publisher for sceneSize

This commit is contained in:
Carson Katri 2022-06-30 14:03:27 -04:00
parent 9d0e2fc067
commit cd661ba4ba
6 changed files with 41 additions and 11 deletions

View File

@ -16,6 +16,7 @@
//
import Foundation
import OpenCombineShim
/// A reconciler modeled after React's
/// [Fiber reconciler](https://reactjs.org/docs/faq-internals.html#what-is-react-fiber)
@ -38,6 +39,8 @@ public final class FiberReconciler<Renderer: FiberRenderer> {
private let caches: Caches
private var sceneSizeCancellable: AnyCancellable?
private var isReconciling = false
public var afterReconcileActions = [() -> ()]()
@ -72,7 +75,7 @@ public final class FiberReconciler<Renderer: FiberRenderer> {
subviews: Subviews,
cache: inout ()
) -> CGSize {
renderer.sceneSize
renderer.sceneSize.value
}
func placeSubviews(
@ -112,6 +115,11 @@ public final class FiberReconciler<Renderer: FiberRenderer> {
// Start by building the initial tree.
alternate = current.createAndBindAlternate?()
reconcile(from: current)
sceneSizeCancellable = renderer.sceneSize.sink { [weak self] _ in
guard let self = self else { return }
self.reconcile(from: self.current)
}
}
public init<A: App>(_ renderer: Renderer, _ app: A) {
@ -136,6 +144,10 @@ public final class FiberReconciler<Renderer: FiberRenderer> {
// Start by building the initial tree.
alternate = current.createAndBindAlternate?()
reconcile(from: current)
sceneSizeCancellable = renderer.sceneSize.sink { [weak self] _ in
guard let self = self else { return }
self.reconcile(from: self.current)
}
}
/// A visitor that performs each pass used by the `FiberReconciler`.

View File

@ -16,6 +16,7 @@
//
import Foundation
import OpenCombineShim
/// A renderer capable of performing mutations specified by a `FiberReconciler`.
public protocol FiberRenderer {
@ -39,7 +40,7 @@ public protocol FiberRenderer {
var defaultEnvironment: EnvironmentValues { get }
/// The size of the window we are rendering in.
var sceneSize: CGSize { get }
var sceneSize: CurrentValueSubject<CGSize, Never> { get }
/// Whether layout is enabled for this renderer.
var useDynamicLayout: Bool { get }

View File

@ -35,7 +35,7 @@ struct LayoutPass: FiberReconcilerPass {
fiber.layout?.placeSubviews(
in: .init(
origin: .zero,
size: fiber.geometry?.dimensions.size ?? reconciler.renderer.sceneSize
size: fiber.geometry?.dimensions.size ?? reconciler.renderer.sceneSize.value
),
proposal: fiber.geometry?.proposal ?? .unspecified,
subviews: caches.layoutSubviews(for: fiber),

View File

@ -17,6 +17,7 @@
import Foundation
import JavaScriptKit
import OpenCombineShim
@_spi(TokamakCore)
import TokamakCore
@_spi(TokamakStaticHTML)
@ -79,9 +80,8 @@ protocol DOMNodeConvertible: HTMLConvertible {
public struct DOMFiberRenderer: FiberRenderer {
public let rootElement: DOMElement
public var sceneSize: CGSize {
.init(width: body.clientWidth.number!, height: body.clientHeight.number!)
}
private let resizeObserver: JSObject?
public let sceneSize: CurrentValueSubject<CGSize, Never>
public let useDynamicLayout: Bool
@ -117,6 +117,21 @@ public struct DOMFiberRenderer: FiberRenderer {
_ = reference.style.setProperty("width", "100vw")
_ = reference.style.setProperty("height", "100vh")
_ = reference.style.setProperty("position", "relative")
let sceneSizePublisher = CurrentValueSubject<CGSize, Never>(
.init(width: body.clientWidth.number!, height: body.clientHeight.number!)
)
sceneSize = sceneSizePublisher
resizeObserver = JSObject.global.ResizeObserver.function!.new(JSClosure { _ in
sceneSizePublisher.send(
.init(width: body.clientWidth.number!, height: body.clientHeight.number!)
)
return .undefined
})
_ = resizeObserver?.observe?(body)
} else {
sceneSize = .init(.zero)
resizeObserver = nil
}
}
@ -207,7 +222,7 @@ public struct DOMFiberRenderer: FiberRenderer {
}
}
return .zero
case let .resizable(.named(name, bundle: bundle), capInsets, resizingMode):
case let .resizable(.named(name, bundle: bundle), _, _):
if proposal == .unspecified {
if let intrinsicSize = image._intrinsicSize {
return intrinsicSize

View File

@ -16,6 +16,7 @@
//
import Foundation
import OpenCombineShim
@_spi(TokamakCore)
import TokamakCore
@ -161,7 +162,7 @@ extension LayoutView: HTMLConvertible {
public struct StaticHTMLFiberRenderer: FiberRenderer {
public let rootElement: HTMLElement
public let defaultEnvironment: EnvironmentValues
public let sceneSize: CGSize
public let sceneSize: CurrentValueSubject<CGSize, Never>
public let useDynamicLayout: Bool
public init() {
@ -173,7 +174,7 @@ public struct StaticHTMLFiberRenderer: FiberRenderer {
@_spi(TokamakStaticHTML)
public init(useDynamicLayout: Bool, sceneSize: CGSize) {
self.useDynamicLayout = useDynamicLayout
self.sceneSize = sceneSize
self.sceneSize = .init(sceneSize)
rootElement = .init(
tag: "body", attributes: ["style": "margin: 0;"], innerHTML: nil, children: []
)

View File

@ -16,6 +16,7 @@
//
import Foundation
import OpenCombineShim
@_spi(TokamakCore) import TokamakCore
public protocol TestFiberPrimitive {
@ -125,7 +126,7 @@ public final class TestFiberElement: FiberElement, CustomStringConvertible {
}
public struct TestFiberRenderer: FiberRenderer {
public let sceneSize: CGSize
public let sceneSize: CurrentValueSubject<CGSize, Never>
public let useDynamicLayout: Bool
public func measureText(
@ -150,7 +151,7 @@ public struct TestFiberRenderer: FiberRenderer {
public init(_ rootElement: ElementType, size: CGSize, useDynamicLayout: Bool = false) {
self.rootElement = rootElement
sceneSize = size
sceneSize = .init(size)
self.useDynamicLayout = useDynamicLayout
}