Fix segmented Text

This commit is contained in:
Carson Katri 2020-08-03 18:27:27 -04:00
parent cb6359431d
commit c0a580653a
2 changed files with 50 additions and 23 deletions

View File

@ -33,14 +33,11 @@ public struct Text: View {
let storage: _Storage
let modifiers: [_Modifier]
@Environment(\.self) public var environment
@Environment(\.font) var font
@Environment(\.foregroundColor) var foregroundColor
@Environment(\.redactionReasons) var redactionReasons
@Environment(\.self) var environment
public enum _Storage {
case verbatim(String)
case segmentedText([Text])
case segmentedText([(_Storage, [_Modifier])])
}
public enum _Modifier: Equatable {
@ -59,8 +56,7 @@ public struct Text: View {
init(storage: _Storage, modifiers: [_Modifier] = []) {
if case let .segmentedText(segments) = storage {
self.storage = .segmentedText(segments.map {
Self(storage: $0.storage,
modifiers: modifiers + $0.modifiers)
($0.0, modifiers + $0.1)
})
} else {
self.storage = storage
@ -81,6 +77,19 @@ public struct Text: View {
}
}
extension Text._Storage {
public var rawText: String {
switch self {
case let .segmentedText(segments):
return segments
.map { $0.0.rawText }
.reduce("", +)
case let .verbatim(text):
return text
}
}
}
/// This is a helper class that works around absence of "package private" access control in Swift
public struct _TextProxy {
public let subject: Text
@ -89,24 +98,17 @@ public struct _TextProxy {
public var storage: Text._Storage { subject.storage }
public var rawText: String {
switch subject.storage {
case let .segmentedText(segments):
return segments
.map { Self($0).rawText }
.reduce("", +)
case let .verbatim(text):
return text
}
subject.storage.rawText
}
public var modifiers: [Text._Modifier] {
[
.font(subject.font),
.color(subject.foregroundColor),
.font(subject.environment.font),
.color(subject.environment.foregroundColor),
] + subject.modifiers
}
public var redactionReasons: RedactionReasons { subject.redactionReasons }
public var environment: EnvironmentValues { subject.environment }
}
public extension Text {
@ -149,6 +151,9 @@ public extension Text {
extension Text {
public static func _concatenating(lhs: Self, rhs: Self) -> Self {
.init(storage: .segmentedText([lhs, rhs]))
.init(storage: .segmentedText([
(lhs.storage, lhs.modifiers),
(rhs.storage, rhs.modifiers),
]))
}
}

View File

@ -89,14 +89,28 @@ extension Font: StylesConvertible {
}
}
private struct TextSpan: AnyHTML {
let content: String
let attributes: [String: String]
var innerHTML: String? { content }
var tag: String { "span" }
}
extension Text: AnyHTML {
public var innerHTML: String? {
switch _TextProxy(self).storage {
let proxy = _TextProxy(self)
switch proxy.storage {
case let .verbatim(text):
return text
case let .segmentedText(segments):
return segments
.map(\.outerHTML)
.map {
TextSpan(content: $0.0.rawText,
attributes: Self.attributes(from: $0.1,
environment: proxy.environment))
.outerHTML
}
.reduce("", +)
}
}
@ -104,7 +118,15 @@ extension Text: AnyHTML {
public var tag: String { "span" }
public var attributes: [String: String] {
let proxy = _TextProxy(self)
let isRedacted = proxy.redactionReasons.contains(.placeholder)
return Self.attributes(from: proxy.modifiers,
environment: proxy.environment)
}
}
extension Text {
static func attributes(from modifiers: [_Modifier],
environment: EnvironmentValues) -> [String: String] {
let isRedacted = environment.redactionReasons.contains(.placeholder)
var font: Font?
var color: Color?
@ -114,7 +136,7 @@ extension Text: AnyHTML {
var baseline: CGFloat?
var strikethrough: (Bool, Color?)?
var underline: (Bool, Color?)?
for modifier in proxy.modifiers {
for modifier in modifiers {
switch modifier {
case let .color(_color):
color = _color