Fix segmented Text
This commit is contained in:
parent
cb6359431d
commit
c0a580653a
|
@ -33,14 +33,11 @@ public struct Text: View {
|
||||||
let storage: _Storage
|
let storage: _Storage
|
||||||
let modifiers: [_Modifier]
|
let modifiers: [_Modifier]
|
||||||
|
|
||||||
@Environment(\.self) public var environment
|
@Environment(\.self) var environment
|
||||||
@Environment(\.font) var font
|
|
||||||
@Environment(\.foregroundColor) var foregroundColor
|
|
||||||
@Environment(\.redactionReasons) var redactionReasons
|
|
||||||
|
|
||||||
public enum _Storage {
|
public enum _Storage {
|
||||||
case verbatim(String)
|
case verbatim(String)
|
||||||
case segmentedText([Text])
|
case segmentedText([(_Storage, [_Modifier])])
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum _Modifier: Equatable {
|
public enum _Modifier: Equatable {
|
||||||
|
@ -59,8 +56,7 @@ public struct Text: View {
|
||||||
init(storage: _Storage, modifiers: [_Modifier] = []) {
|
init(storage: _Storage, modifiers: [_Modifier] = []) {
|
||||||
if case let .segmentedText(segments) = storage {
|
if case let .segmentedText(segments) = storage {
|
||||||
self.storage = .segmentedText(segments.map {
|
self.storage = .segmentedText(segments.map {
|
||||||
Self(storage: $0.storage,
|
($0.0, modifiers + $0.1)
|
||||||
modifiers: modifiers + $0.modifiers)
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
self.storage = storage
|
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
|
/// This is a helper class that works around absence of "package private" access control in Swift
|
||||||
public struct _TextProxy {
|
public struct _TextProxy {
|
||||||
public let subject: Text
|
public let subject: Text
|
||||||
|
@ -89,24 +98,17 @@ public struct _TextProxy {
|
||||||
|
|
||||||
public var storage: Text._Storage { subject.storage }
|
public var storage: Text._Storage { subject.storage }
|
||||||
public var rawText: String {
|
public var rawText: String {
|
||||||
switch subject.storage {
|
subject.storage.rawText
|
||||||
case let .segmentedText(segments):
|
|
||||||
return segments
|
|
||||||
.map { Self($0).rawText }
|
|
||||||
.reduce("", +)
|
|
||||||
case let .verbatim(text):
|
|
||||||
return text
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public var modifiers: [Text._Modifier] {
|
public var modifiers: [Text._Modifier] {
|
||||||
[
|
[
|
||||||
.font(subject.font),
|
.font(subject.environment.font),
|
||||||
.color(subject.foregroundColor),
|
.color(subject.environment.foregroundColor),
|
||||||
] + subject.modifiers
|
] + subject.modifiers
|
||||||
}
|
}
|
||||||
|
|
||||||
public var redactionReasons: RedactionReasons { subject.redactionReasons }
|
public var environment: EnvironmentValues { subject.environment }
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension Text {
|
public extension Text {
|
||||||
|
@ -149,6 +151,9 @@ public extension Text {
|
||||||
|
|
||||||
extension Text {
|
extension Text {
|
||||||
public static func _concatenating(lhs: Self, rhs: Self) -> Self {
|
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),
|
||||||
|
]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
extension Text: AnyHTML {
|
||||||
public var innerHTML: String? {
|
public var innerHTML: String? {
|
||||||
switch _TextProxy(self).storage {
|
let proxy = _TextProxy(self)
|
||||||
|
switch proxy.storage {
|
||||||
case let .verbatim(text):
|
case let .verbatim(text):
|
||||||
return text
|
return text
|
||||||
case let .segmentedText(segments):
|
case let .segmentedText(segments):
|
||||||
return segments
|
return segments
|
||||||
.map(\.outerHTML)
|
.map {
|
||||||
|
TextSpan(content: $0.0.rawText,
|
||||||
|
attributes: Self.attributes(from: $0.1,
|
||||||
|
environment: proxy.environment))
|
||||||
|
.outerHTML
|
||||||
|
}
|
||||||
.reduce("", +)
|
.reduce("", +)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +118,15 @@ extension Text: AnyHTML {
|
||||||
public var tag: String { "span" }
|
public var tag: String { "span" }
|
||||||
public var attributes: [String: String] {
|
public var attributes: [String: String] {
|
||||||
let proxy = _TextProxy(self)
|
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 font: Font?
|
||||||
var color: Color?
|
var color: Color?
|
||||||
|
@ -114,7 +136,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 proxy.modifiers {
|
for modifier in modifiers {
|
||||||
switch modifier {
|
switch modifier {
|
||||||
case let .color(_color):
|
case let .color(_color):
|
||||||
color = _color
|
color = _color
|
||||||
|
|
Loading…
Reference in New Issue