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.
|
// Created by Max Desiatov on 28/11/2018.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import Runtime
|
||||||
|
|
||||||
public class MountedView<R: Renderer> {
|
public class MountedView<R: Renderer> {
|
||||||
public internal(set) var view: AnyView
|
public internal(set) var view: AnyView
|
||||||
|
|
||||||
|
@ -39,13 +41,46 @@ extension View {
|
||||||
func makeMountedView<R: Renderer>(_ parentTarget: R.TargetType,
|
func makeMountedView<R: Renderer>(_ parentTarget: R.TargetType,
|
||||||
_ environmentValues: EnvironmentValues)
|
_ environmentValues: EnvironmentValues)
|
||||||
-> MountedView<R> {
|
-> 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 {
|
if anyView.type == EmptyView.self {
|
||||||
return MountedNull(anyView)
|
return MountedNull(anyView)
|
||||||
} else if anyView.bodyType == Never.self && !(anyView.type is ViewDeferredToRenderer.Type) {
|
} else if anyView.bodyType == Never.self && !(anyView.type is ViewDeferredToRenderer.Type) {
|
||||||
return MountedHostView(anyView, parentTarget, environmentValues)
|
return MountedHostView(anyView, parentTarget, modifiedEnv)
|
||||||
} else {
|
} 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)
|
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)
|
let result = compositeView.view.bodyClosure(compositeView.view.view)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
|
@ -17,7 +17,9 @@
|
||||||
|
|
||||||
public struct Text: View {
|
public struct Text: View {
|
||||||
let content: String
|
let content: String
|
||||||
public let _modifiers: [_Modifier]
|
let modifiers: [_Modifier]
|
||||||
|
|
||||||
|
@Environment(\.font) var font: Font?
|
||||||
|
|
||||||
public enum _Modifier: Equatable {
|
public enum _Modifier: Equatable {
|
||||||
case color(Color?)
|
case color(Color?)
|
||||||
|
@ -34,7 +36,7 @@ public struct Text: View {
|
||||||
|
|
||||||
init(content: String, modifiers: [_Modifier] = []) {
|
init(content: String, modifiers: [_Modifier] = []) {
|
||||||
self.content = content
|
self.content = content
|
||||||
_modifiers = modifiers
|
self.modifiers = modifiers
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(verbatim content: String) {
|
public init(verbatim content: String) {
|
||||||
|
@ -57,46 +59,51 @@ public struct _TextProxy {
|
||||||
public init(_ subject: Text) { self.subject = subject }
|
public init(_ subject: Text) { self.subject = subject }
|
||||||
|
|
||||||
public var content: String { subject.content }
|
public var content: String { subject.content }
|
||||||
|
public var modifiers: [Text._Modifier] {
|
||||||
|
[
|
||||||
|
.font(subject.font),
|
||||||
|
] + subject.modifiers
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension Text {
|
public extension Text {
|
||||||
func foregroundColor(_ color: Color?) -> 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 {
|
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 {
|
func fontWeight(_ weight: Font.Weight?) -> Text {
|
||||||
.init(content: content, modifiers: _modifiers + [.weight(weight)])
|
.init(content: content, modifiers: modifiers + [.weight(weight)])
|
||||||
}
|
}
|
||||||
|
|
||||||
func bold() -> Text {
|
func bold() -> Text {
|
||||||
.init(content: content, modifiers: _modifiers + [.weight(.bold)])
|
.init(content: content, modifiers: modifiers + [.weight(.bold)])
|
||||||
}
|
}
|
||||||
|
|
||||||
func italic() -> Text {
|
func italic() -> Text {
|
||||||
.init(content: content, modifiers: _modifiers + [.italic])
|
.init(content: content, modifiers: modifiers + [.italic])
|
||||||
}
|
}
|
||||||
|
|
||||||
func strikethrough(_ active: Bool = true, color: Color? = nil) -> Text {
|
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 {
|
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 {
|
func kerning(_ kerning: CGFloat) -> Text {
|
||||||
.init(content: content, modifiers: _modifiers + [.kerning(kerning)])
|
.init(content: content, modifiers: modifiers + [.kerning(kerning)])
|
||||||
}
|
}
|
||||||
|
|
||||||
func tracking(_ tracking: CGFloat) -> Text {
|
func tracking(_ tracking: CGFloat) -> Text {
|
||||||
.init(content: content, modifiers: _modifiers + [.tracking(tracking)])
|
.init(content: content, modifiers: modifiers + [.tracking(tracking)])
|
||||||
}
|
}
|
||||||
|
|
||||||
func baselineOffset(_ baselineOffset: CGFloat) -> Text {
|
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 baseline: CGFloat?
|
||||||
var strikethrough: (Bool, Color?)?
|
var strikethrough: (Bool, Color?)?
|
||||||
var underline: (Bool, Color?)?
|
var underline: (Bool, Color?)?
|
||||||
for modifier in _modifiers {
|
for modifier in _TextProxy(self).modifiers {
|
||||||
switch modifier {
|
switch modifier {
|
||||||
case let .color(_color):
|
case let .color(_color):
|
||||||
color = _color
|
color = _color
|
||||||
|
|
|
@ -50,7 +50,7 @@ let renderer = DOMRenderer(
|
||||||
Spacer()
|
Spacer()
|
||||||
Text("Forced to bottom.")
|
Text("Forced to bottom.")
|
||||||
EnvironmentDemo()
|
EnvironmentDemo()
|
||||||
.font(.system(size: 21))
|
.font(.system(size: 8))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
div
|
div
|
||||||
|
|
Loading…
Reference in New Issue