diff --git a/Sources/TokamakCore/MountedViews/MountedView.swift b/Sources/TokamakCore/MountedViews/MountedView.swift index b7262ee5..1f9baf8a 100644 --- a/Sources/TokamakCore/MountedViews/MountedView.swift +++ b/Sources/TokamakCore/MountedViews/MountedView.swift @@ -15,6 +15,8 @@ // Created by Max Desiatov on 28/11/2018. // +import Runtime + public class MountedView { public internal(set) var view: AnyView @@ -39,13 +41,46 @@ extension View { func makeMountedView(_ parentTarget: R.TargetType, _ environmentValues: EnvironmentValues) -> MountedView { - 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) } } } diff --git a/Sources/TokamakCore/StackReconciler.swift b/Sources/TokamakCore/StackReconciler.swift index ce270377..1b5b026f 100644 --- a/Sources/TokamakCore/StackReconciler.swift +++ b/Sources/TokamakCore/StackReconciler.swift @@ -89,29 +89,6 @@ public final class StackReconciler { 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 diff --git a/Sources/TokamakCore/Views/Text.swift b/Sources/TokamakCore/Views/Text.swift index 15a1fbb2..fa9ec60f 100644 --- a/Sources/TokamakCore/Views/Text.swift +++ b/Sources/TokamakCore/Views/Text.swift @@ -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)]) } } diff --git a/Sources/TokamakDOM/Views/Text.swift b/Sources/TokamakDOM/Views/Text.swift index b19e0388..4f5d3184 100644 --- a/Sources/TokamakDOM/Views/Text.swift +++ b/Sources/TokamakDOM/Views/Text.swift @@ -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 diff --git a/Sources/TokamakDemo/main.swift b/Sources/TokamakDemo/main.swift index 586f33de..f8d566fc 100644 --- a/Sources/TokamakDemo/main.swift +++ b/Sources/TokamakDemo/main.swift @@ -50,7 +50,7 @@ let renderer = DOMRenderer( Spacer() Text("Forced to bottom.") EnvironmentDemo() - .font(.system(size: 21)) + .font(.system(size: 8)) } }, div