Allow @Environment on all MountedViews (#146)
This commit is contained in:
parent
1632db77b9
commit
525cefe6bc
|
@ -15,6 +15,8 @@
|
|||
// Created by Max Desiatov on 28/11/2018.
|
||||
//
|
||||
|
||||
import Runtime
|
||||
|
||||
public class MountedView<R: Renderer> {
|
||||
public internal(set) var view: AnyView
|
||||
|
||||
|
@ -39,13 +41,46 @@ extension View {
|
|||
func makeMountedView<R: Renderer>(_ parentTarget: R.TargetType,
|
||||
_ environmentValues: EnvironmentValues)
|
||||
-> MountedView<R> {
|
||||
let anyView = self as? AnyView ?? AnyView(self)
|
||||
// Find Environment changes
|
||||
var modifiedEnv = environmentValues
|
||||
var injectableView = self
|
||||
if let any = injectableView as? AnyView {
|
||||
// swiftlint:disable force_try
|
||||
// Extract the view from the AnyView for modification
|
||||
var extractedView = any.view
|
||||
let viewInfo = try! typeInfo(of: any.type)
|
||||
if viewInfo
|
||||
.genericTypes
|
||||
.filter({ $0 is EnvironmentModifier.Type }).count > 0 {
|
||||
// Apply Environment changes:
|
||||
if let modifier = try? viewInfo
|
||||
.property(named: "modifier")
|
||||
.get(from: any.view) as? EnvironmentModifier {
|
||||
modifier.modifyEnvironment(&modifiedEnv)
|
||||
}
|
||||
}
|
||||
// Inject @Environment values
|
||||
// In the future we can also inject @EnvironmentObject values
|
||||
for prop in viewInfo.properties.filter({ $0.type is EnvironmentReader.Type }) {
|
||||
// swiftlint:disable force_cast
|
||||
var wrapper = try! prop.get(from: any.view) as! EnvironmentReader
|
||||
wrapper.setContent(from: modifiedEnv)
|
||||
try! prop.set(value: wrapper, on: &extractedView)
|
||||
// swiftlint:enable force_cast
|
||||
}
|
||||
// Set the extractedView back on the AnyView after modification
|
||||
let anyViewInfo = try! typeInfo(of: AnyView.self)
|
||||
try! anyViewInfo.property(named: "view").set(value: extractedView, on: &injectableView)
|
||||
// swiftlint:enable force_try
|
||||
}
|
||||
|
||||
let anyView = injectableView as? AnyView ?? AnyView(injectableView)
|
||||
if anyView.type == EmptyView.self {
|
||||
return MountedNull(anyView)
|
||||
} else if anyView.bodyType == Never.self && !(anyView.type is ViewDeferredToRenderer.Type) {
|
||||
return MountedHostView(anyView, parentTarget, environmentValues)
|
||||
return MountedHostView(anyView, parentTarget, modifiedEnv)
|
||||
} else {
|
||||
return MountedCompositeView(anyView, parentTarget, environmentValues)
|
||||
return MountedCompositeView(anyView, parentTarget, modifiedEnv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,29 +89,6 @@ public final class StackReconciler<R: Renderer> {
|
|||
try! stateProperty.set(value: state, on: &compositeView.view.view)
|
||||
}
|
||||
|
||||
let viewInfo = try! typeInfo(of: compositeView.view.type)
|
||||
if viewInfo
|
||||
.genericTypes
|
||||
.filter({ $0 is EnvironmentModifier.Type }).count > 0 {
|
||||
// Apply Environment changes:
|
||||
if let modifier = try? viewInfo
|
||||
.property(named: "modifier")
|
||||
.get(from: compositeView.view.view) as? EnvironmentModifier {
|
||||
modifier.modifyEnvironment(&compositeView.environmentValues)
|
||||
}
|
||||
}
|
||||
|
||||
// Inject @Environment values
|
||||
// In the future we can also inject @EnvironmentObject values
|
||||
for prop in viewInfo.properties.filter({ $0.type is EnvironmentReader.Type }) {
|
||||
// swiftlint:disable force_cast
|
||||
var wrapper = try! prop.get(from: compositeView.view.view) as! EnvironmentReader
|
||||
wrapper.setContent(from: compositeView.environmentValues)
|
||||
try! prop.set(value: wrapper, on: &compositeView.view.view)
|
||||
// swiftlint:enable force_cast
|
||||
}
|
||||
// swiftlint:enable force_try
|
||||
|
||||
let result = compositeView.view.bodyClosure(compositeView.view.view)
|
||||
|
||||
return result
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
|
||||
public struct Text: View {
|
||||
let content: String
|
||||
public let _modifiers: [_Modifier]
|
||||
let modifiers: [_Modifier]
|
||||
|
||||
@Environment(\.font) var font: Font?
|
||||
|
||||
public enum _Modifier: Equatable {
|
||||
case color(Color?)
|
||||
|
@ -34,7 +36,7 @@ public struct Text: View {
|
|||
|
||||
init(content: String, modifiers: [_Modifier] = []) {
|
||||
self.content = content
|
||||
_modifiers = modifiers
|
||||
self.modifiers = modifiers
|
||||
}
|
||||
|
||||
public init(verbatim content: String) {
|
||||
|
@ -57,46 +59,51 @@ public struct _TextProxy {
|
|||
public init(_ subject: Text) { self.subject = subject }
|
||||
|
||||
public var content: String { subject.content }
|
||||
public var modifiers: [Text._Modifier] {
|
||||
[
|
||||
.font(subject.font),
|
||||
] + subject.modifiers
|
||||
}
|
||||
}
|
||||
|
||||
public extension Text {
|
||||
func foregroundColor(_ color: Color?) -> Text {
|
||||
.init(content: content, modifiers: _modifiers + [.color(color)])
|
||||
.init(content: content, modifiers: modifiers + [.color(color)])
|
||||
}
|
||||
|
||||
func font(_ font: Font?) -> Text {
|
||||
.init(content: content, modifiers: _modifiers + [.font(font)])
|
||||
.init(content: content, modifiers: modifiers + [.font(font)])
|
||||
}
|
||||
|
||||
func fontWeight(_ weight: Font.Weight?) -> Text {
|
||||
.init(content: content, modifiers: _modifiers + [.weight(weight)])
|
||||
.init(content: content, modifiers: modifiers + [.weight(weight)])
|
||||
}
|
||||
|
||||
func bold() -> Text {
|
||||
.init(content: content, modifiers: _modifiers + [.weight(.bold)])
|
||||
.init(content: content, modifiers: modifiers + [.weight(.bold)])
|
||||
}
|
||||
|
||||
func italic() -> Text {
|
||||
.init(content: content, modifiers: _modifiers + [.italic])
|
||||
.init(content: content, modifiers: modifiers + [.italic])
|
||||
}
|
||||
|
||||
func strikethrough(_ active: Bool = true, color: Color? = nil) -> Text {
|
||||
.init(content: content, modifiers: _modifiers + [.strikethrough(active, color)])
|
||||
.init(content: content, modifiers: modifiers + [.strikethrough(active, color)])
|
||||
}
|
||||
|
||||
func underline(_ active: Bool = true, color: Color? = nil) -> Text {
|
||||
.init(content: content, modifiers: _modifiers + [.underline(active, color)])
|
||||
.init(content: content, modifiers: modifiers + [.underline(active, color)])
|
||||
}
|
||||
|
||||
func kerning(_ kerning: CGFloat) -> Text {
|
||||
.init(content: content, modifiers: _modifiers + [.kerning(kerning)])
|
||||
.init(content: content, modifiers: modifiers + [.kerning(kerning)])
|
||||
}
|
||||
|
||||
func tracking(_ tracking: CGFloat) -> Text {
|
||||
.init(content: content, modifiers: _modifiers + [.tracking(tracking)])
|
||||
.init(content: content, modifiers: modifiers + [.tracking(tracking)])
|
||||
}
|
||||
|
||||
func baselineOffset(_ baselineOffset: CGFloat) -> Text {
|
||||
.init(content: content, modifiers: _modifiers + [.baseline(baselineOffset)])
|
||||
.init(content: content, modifiers: modifiers + [.baseline(baselineOffset)])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ extension Text: AnyHTML {
|
|||
var baseline: CGFloat?
|
||||
var strikethrough: (Bool, Color?)?
|
||||
var underline: (Bool, Color?)?
|
||||
for modifier in _modifiers {
|
||||
for modifier in _TextProxy(self).modifiers {
|
||||
switch modifier {
|
||||
case let .color(_color):
|
||||
color = _color
|
||||
|
|
|
@ -50,7 +50,7 @@ let renderer = DOMRenderer(
|
|||
Spacer()
|
||||
Text("Forced to bottom.")
|
||||
EnvironmentDemo()
|
||||
.font(.system(size: 21))
|
||||
.font(.system(size: 8))
|
||||
}
|
||||
},
|
||||
div
|
||||
|
|
Loading…
Reference in New Issue