Skip to content

Commit d9842f2

Browse files
committed
LabeledContentStyle's now respect labelsHidden correctly
1 parent b7800ca commit d9842f2

3 files changed

Lines changed: 99 additions & 96 deletions

File tree

Sources/SwiftUIBackports/Shared/LabeledContent/LabeledContent.swift

Lines changed: 64 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -123,40 +123,62 @@ extension Backport where Wrapped == Any {
123123
///
124124
/// You can set label styles using the ``View/labeledContentStyle(_:)``
125125
/// modifier. You can also build custom styles using ``LabeledContentStyle``.
126-
public struct LabeledContent<Label, Content> {
126+
public struct LabeledContent<Label, Content>: View {
127+
@EnvironmentContains(key: "LabelsHiddenKey") private var isHidden
127128
@Environment(\.backportLabeledContentStyle) private var style
129+
128130
let config: LabeledContentStyleConfiguration
131+
129132
public var body: some View {
130-
style.makeBody(configuration: config)
133+
style.makeBody(configuration: config.labelHidden(isHidden))
134+
}
135+
136+
/// Creates labeled content based on a labeled content style configuration.
137+
///
138+
/// You can use this initializer within the
139+
/// ``LabeledContentStyle/makeBody(configuration:)`` method of a
140+
/// ``LabeledContentStyle`` to create a labeled content instance.
141+
/// This is useful for custom styles that only modify the current style,
142+
/// as opposed to implementing a brand new style.
143+
///
144+
/// For example, the following style adds a red border around the labeled
145+
/// content, but otherwise preserves the current style:
146+
///
147+
/// struct RedBorderLabeledContentStyle: LabeledContentStyle {
148+
/// func makeBody(configuration: Configuration) -> some View {
149+
/// LabeledContent(configuration)
150+
/// .border(.red)
151+
/// }
152+
/// }
153+
///
154+
/// - Parameter configuration: The properties of the labeled content
155+
public init(_ config: Backport.LabeledContentStyleConfiguration) {
156+
self.config = config
131157
}
132158
}
133159

134160
}
135161

136-
extension Backport.LabeledContent where Wrapped == Any, Label == Backport<Any>.LabeledContentStyleConfiguration.Label, Content == Backport<Any>.LabeledContentStyleConfiguration.Content {
162+
extension Backport.LabeledContent where Wrapped == Any, Label: View, Content: View {
137163

138-
/// Creates labeled content based on a labeled content style configuration.
139-
///
140-
/// You can use this initializer within the
141-
/// ``LabeledContentStyle/makeBody(configuration:)`` method of a
142-
/// ``LabeledContentStyle`` to create a labeled content instance.
143-
/// This is useful for custom styles that only modify the current style,
144-
/// as opposed to implementing a brand new style.
145-
///
146-
/// For example, the following style adds a red border around the labeled
147-
/// content, but otherwise preserves the current style:
164+
/// Creates a labeled view that generates its label from a localized string
165+
/// key.
148166
///
149-
/// struct RedBorderLabeledContentStyle: LabeledContentStyle {
150-
/// func makeBody(configuration: Configuration) -> some View {
151-
/// LabeledContent(configuration)
152-
/// .border(.red)
153-
/// }
154-
/// }
167+
/// This initializer creates a ``Text`` label on your behalf, and treats the
168+
/// localized key similar to ``Text/init(_:tableName:bundle:comment:)``. See
169+
/// `Text` for more information about localizing strings.
155170
///
156-
/// - Parameter configuration: The properties of the labeled content
157-
public init(_ config: Backport.LabeledContentStyleConfiguration) {
158-
self.config = config
171+
/// - Parameters:
172+
/// - titleKey: The key for the view's localized title, that describes
173+
/// the purpose of the view.
174+
/// - content: The value content being labeled.
175+
public init(@ViewBuilder content: () -> Content, @ViewBuilder label: () -> Label) {
176+
config = .init(
177+
label: label(),
178+
content: content()
179+
)
159180
}
181+
160182
}
161183

162184
extension Backport.LabeledContent where Wrapped == Any, Label == Text, Content : View {
@@ -173,10 +195,11 @@ extension Backport.LabeledContent where Wrapped == Any, Label == Text, Content :
173195
/// the purpose of the view.
174196
/// - content: The value content being labeled.
175197
public init(_ titleKey: LocalizedStringKey, @ViewBuilder content: () -> Content) {
176-
config = .init(
177-
label: Text(titleKey),
178-
content: content()
179-
)
198+
self.init {
199+
content()
200+
} label: {
201+
Text(titleKey)
202+
}
180203
}
181204

182205
/// Creates a labeled view that generates its label from a string.
@@ -189,32 +212,11 @@ extension Backport.LabeledContent where Wrapped == Any, Label == Text, Content :
189212
/// - title: A string that describes the purpose of the view.
190213
/// - content: The value content being labeled.
191214
public init<S>(_ title: S, @ViewBuilder content: () -> Content) where S: StringProtocol {
192-
config = .init(
193-
label: Text(title),
194-
content: content()
195-
)
196-
}
197-
198-
}
199-
200-
extension Backport.LabeledContent: View where Wrapped == Any, Label: View, Content: View {
201-
202-
/// Creates a labeled view that generates its label from a localized string
203-
/// key.
204-
///
205-
/// This initializer creates a ``Text`` label on your behalf, and treats the
206-
/// localized key similar to ``Text/init(_:tableName:bundle:comment:)``. See
207-
/// `Text` for more information about localizing strings.
208-
///
209-
/// - Parameters:
210-
/// - titleKey: The key for the view's localized title, that describes
211-
/// the purpose of the view.
212-
/// - content: The value content being labeled.
213-
public init(@ViewBuilder content: () -> Content, @ViewBuilder label: () -> Label) {
214-
config = .init(
215-
label: label(),
216-
content: content()
217-
)
215+
self.init {
216+
content()
217+
} label: {
218+
Text(title)
219+
}
218220
}
219221

220222
}
@@ -238,9 +240,11 @@ extension Backport.LabeledContent where Wrapped == Any, Label == Text, Content =
238240
/// the purpose of the view.
239241
/// - value: The value being labeled.
240242
public init<S: StringProtocol>(_ titleKey: LocalizedStringKey, value: S) {
241-
config = .init(
242-
label: Text(titleKey),
243-
content: Text(value))
243+
self.init {
244+
Text(value)
245+
} label: {
246+
Text(titleKey)
247+
}
244248
}
245249

246250
/// Creates a labeled informational view.
@@ -259,10 +263,11 @@ extension Backport.LabeledContent where Wrapped == Any, Label == Text, Content =
259263
/// - title: A string that describes the purpose of the view.
260264
/// - value: The value being labeled.
261265
public init<S1: StringProtocol, S2: StringProtocol>(_ title: S1, value: S2) {
262-
config = .init(
263-
label: Text(title),
264-
content: Text(value)
265-
)
266+
self.init {
267+
Text(value)
268+
} label: {
269+
Text(title)
270+
}
266271
}
267272

268273
}

Sources/SwiftUIBackports/Shared/LabeledContent/LabeledContentStyleConfiguration.swift

Lines changed: 17 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,53 +8,39 @@ extension Backport where Wrapped == Any {
88

99
/// The properties of a labeled content instance.
1010
public struct LabeledContentStyleConfiguration {
11+
private struct Label<Content: View>: View {
12+
let isHidden: Bool
13+
let content: Content
1114

12-
/// A type-erased label of a labeled content instance.
13-
public struct Label: View {
14-
@EnvironmentContains(key: "LabelsHiddenKey") private var isHidden
15-
let view: AnyView
1615
public var body: some View {
17-
if isHidden {
18-
EmptyView()
19-
} else {
20-
view
16+
if !isHidden {
17+
content
2118
}
2219
}
23-
init<V: View>(_ view: V) {
24-
self.view = .init(view)
25-
}
2620
}
2721

28-
/// A type-erased content of a labeled content instance.
29-
public struct Content: View {
30-
@EnvironmentContains(key: "LabelsHiddenKey") private var isHidden
31-
let view: AnyView
32-
public var body: some View {
33-
view
34-
.foregroundColor(isHidden ? .primary : .secondary)
35-
.frame(maxWidth: .infinity, alignment: isHidden ? .leading : .trailing)
36-
}
37-
init<V: View>(_ view: V) {
38-
self.view = .init(view)
39-
}
40-
}
22+
var labelHidden: Bool = false
23+
24+
private let _label: AnyView
4125

4226
/// The label of the labeled content instance.
43-
public let label: Label
27+
public var label: some View {
28+
Label(isHidden: labelHidden, content: _label)
29+
}
4430

4531
/// The content of the labeled content instance.
46-
public let content: Content
32+
public let content: AnyView
4733

4834
internal init<L: View, C: View>(label: L, content: C) {
49-
self.label = .init(label)
35+
_label = .init(label)
5036
self.content = .init(content)
5137
}
5238

53-
internal init<L: View, C: View>(@ViewBuilder content: () -> C, @ViewBuilder label: () -> L) {
54-
self.content = .init(content())
55-
self.label = .init(label())
39+
func labelHidden(_ hidden: Bool) -> Self {
40+
var copy = self
41+
copy.labelHidden = hidden
42+
return copy
5643
}
57-
5844
}
5945

6046
}

Sources/SwiftUIBackports/Shared/LabeledContent/Styles/AutomaticLabeledContentStyle.swift

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,26 @@ import SwiftUI
33
extension Backport where Wrapped == Any {
44

55
public struct AutomaticLabeledContentStyle: BackportLabeledContentStyle {
6-
public func makeBody(configuration: Configuration) -> some View {
7-
HStack(alignment: .firstTextBaseline) {
8-
configuration.label
9-
Spacer()
10-
configuration.content
11-
.multilineTextAlignment(.trailing)
6+
private struct Content: View {
7+
let configuration: Configuration
8+
9+
var body: some View {
10+
if configuration.labelHidden {
11+
configuration.content
12+
} else {
13+
HStack(alignment: .firstTextBaseline) {
14+
configuration.label
15+
Spacer()
16+
configuration.content
17+
.foregroundColor(.secondary)
18+
}
19+
}
1220
}
1321
}
22+
23+
public func makeBody(configuration: Configuration) -> some View {
24+
Content(configuration: configuration)
25+
}
1426
}
1527

1628
}

0 commit comments

Comments
 (0)