Skip to content

Commit 0efe413

Browse files
committed
feat: support if / else and more
1 parent 8b7d67d commit 0efe413

File tree

3 files changed

+132
-41
lines changed

3 files changed

+132
-41
lines changed

Sources/View+Modifiers.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,20 @@ extension View {
1010
modifier(ApplyViewModifiers(modifiers))
1111
}
1212
}
13+
14+
/// Applies set of modifiers to a view and returns a new view.
15+
public struct ApplyViewModifiers<Modifiers>: ViewModifier where Modifiers: ViewModifier {
16+
private let modifiers: Modifiers
17+
18+
/// Structure to apply a set of modifiers to a view.
19+
///
20+
/// - Parameters
21+
/// - modifiers: closure returning a modifier
22+
public init(@ViewModifierBuilder _ modifiers: () -> Modifiers) {
23+
self.modifiers = modifiers()
24+
}
25+
26+
public func body(content: Content) -> some View {
27+
content.modifier(modifiers)
28+
}
29+
}

Sources/ViewModifierBuilder.swift

Lines changed: 115 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,33 @@
11
import SwiftUI
22

3-
/// A custom parameter attribute that concats many ViewModifers.
3+
public struct V: ViewModifier {
4+
public func body(content: Content) -> some View {
5+
content
6+
}
7+
}
8+
9+
public struct V2: ViewModifier {
10+
public func body(content: Content) -> some View {
11+
content
12+
}
13+
}
14+
15+
/// A custom parameter attribute that constructs modifiers from closures.
16+
///
17+
/// You typically use ``ViewModiferBuilder`` as a parameter attribute for child
18+
/// modifier-producing closure parameters, allowing those closures to provide
19+
/// multiple child modifiers.
20+
///
421
@resultBuilder public enum ViewModifierBuilder {
522

6-
/// Builds an empty ViewModifer from a block containing no statements.
23+
/// Builds an empty modifier from a block containing no statements.
724
public static func buildBlock() -> EmptyModifier {
825
EmptyModifier()
926
}
1027

11-
/// Passes a single view written as a child view through unmodified.
28+
/// Passes a single modifier written as a child modifier through unmodified.
29+
/// An example of a single modifier written as a child modifier is
30+
/// `{ ExampleModifier() }`.
1231
public static func buildBlock<Modifier>(_ modifier: Modifier) -> Modifier
1332
where Modifier: ViewModifier {
1433
modifier
@@ -20,27 +39,29 @@ import SwiftUI
2039
}
2140

2241
public static func buildBlock<M0, M1, M2>(_ m0: M0, _ m1: M1, _ m2: M2)
23-
-> some ViewModifier where M0: ViewModifier, M1: ViewModifier, M2: ViewModifier
24-
{
42+
-> ModifiedContent<ModifiedContent<M0, M1>, M2>
43+
where M0: ViewModifier, M1: ViewModifier, M2: ViewModifier {
2544
m0.concat(m1).concat(m2)
2645
}
2746

2847
public static func buildBlock<M0, M1, M2, M3>(_ m0: M0, _ m1: M1, _ m2: M2, _ m3: M3)
29-
-> some ViewModifier
48+
-> ModifiedContent<ModifiedContent<ModifiedContent<M0, M1>, M2>, M3>
3049
where M0: ViewModifier, M1: ViewModifier, M2: ViewModifier, M3: ViewModifier {
3150
m0.concat(m1).concat(m2).concat(m3)
3251
}
3352

3453
public static func buildBlock<M0, M1, M2, M3, M4>(
3554
_ m0: M0, _ m1: M1, _ m2: M2, _ m3: M3, _ m4: M4
36-
) -> some ViewModifier
55+
) -> ModifiedContent<ModifiedContent<ModifiedContent<ModifiedContent<M0, M1>, M2>, M3>, M4>
3756
where M0: ViewModifier, M1: ViewModifier, M2: ViewModifier, M3: ViewModifier, M4: ViewModifier {
3857
m0.concat(m1).concat(m2).concat(m3).concat(m4)
3958
}
4059

4160
public static func buildBlock<M0, M1, M2, M3, M4, M5>(
4261
_ m0: M0, _ m1: M1, _ m2: M2, _ m3: M3, _ m4: M4, _ m5: M5
43-
) -> some ViewModifier
62+
) -> ModifiedContent<
63+
ModifiedContent<ModifiedContent<ModifiedContent<ModifiedContent<M0, M1>, M2>, M3>, M4>, M5
64+
>
4465
where
4566
M0: ViewModifier, M1: ViewModifier, M2: ViewModifier, M3: ViewModifier, M4: ViewModifier,
4667
M5: ViewModifier
@@ -50,7 +71,11 @@ import SwiftUI
5071

5172
public static func buildBlock<M0, M1, M2, M3, M4, M5, M6>(
5273
_ m0: M0, _ m1: M1, _ m2: M2, _ m3: M3, _ m4: M4, _ m5: M5, _ m6: M6
53-
) -> some ViewModifier
74+
) -> ModifiedContent<
75+
ModifiedContent<
76+
ModifiedContent<ModifiedContent<ModifiedContent<ModifiedContent<M0, M1>, M2>, M3>, M4>, M5
77+
>, M6
78+
>
5479
where
5580
M0: ViewModifier, M1: ViewModifier, M2: ViewModifier, M3: ViewModifier, M4: ViewModifier,
5681
M5: ViewModifier, M6: ViewModifier
@@ -60,7 +85,13 @@ import SwiftUI
6085

6186
public static func buildBlock<M0, M1, M2, M3, M4, M5, M6, M7>(
6287
_ m0: M0, _ m1: M1, _ m2: M2, _ m3: M3, _ m4: M4, _ m5: M5, _ m6: M6, _ m7: M7
63-
) -> some ViewModifier
88+
) -> ModifiedContent<
89+
ModifiedContent<
90+
ModifiedContent<
91+
ModifiedContent<ModifiedContent<ModifiedContent<ModifiedContent<M0, M1>, M2>, M3>, M4>, M5
92+
>, M6
93+
>, M7
94+
>
6495
where
6596
M0: ViewModifier, M1: ViewModifier, M2: ViewModifier, M3: ViewModifier, M4: ViewModifier,
6697
M5: ViewModifier, M6: ViewModifier, M7: ViewModifier
@@ -70,7 +101,15 @@ import SwiftUI
70101

71102
public static func buildBlock<M0, M1, M2, M3, M4, M5, M6, M7, M8>(
72103
_ m0: M0, _ m1: M1, _ m2: M2, _ m3: M3, _ m4: M4, _ m5: M5, _ m6: M6, _ m7: M7, _ m8: M8
73-
) -> some ViewModifier
104+
) -> ModifiedContent<
105+
ModifiedContent<
106+
ModifiedContent<
107+
ModifiedContent<
108+
ModifiedContent<ModifiedContent<ModifiedContent<ModifiedContent<M0, M1>, M2>, M3>, M4>, M5
109+
>, M6
110+
>, M7
111+
>, M8
112+
>
74113
where
75114
M0: ViewModifier, M1: ViewModifier, M2: ViewModifier, M3: ViewModifier, M4: ViewModifier,
76115
M5: ViewModifier, M6: ViewModifier, M7: ViewModifier, M8: ViewModifier
@@ -81,7 +120,18 @@ import SwiftUI
81120
public static func buildBlock<M0, M1, M2, M3, M4, M5, M6, M7, M8, M9>(
82121
_ m0: M0, _ m1: M1, _ m2: M2, _ m3: M3, _ m4: M4, _ m5: M5, _ m6: M6, _ m7: M7, _ m8: M8,
83122
_ m9: M9
84-
) -> some ViewModifier
123+
) -> ModifiedContent<
124+
ModifiedContent<
125+
ModifiedContent<
126+
ModifiedContent<
127+
ModifiedContent<
128+
ModifiedContent<ModifiedContent<ModifiedContent<ModifiedContent<M0, M1>, M2>, M3>, M4>,
129+
M5
130+
>, M6
131+
>, M7
132+
>, M8
133+
>, M9
134+
>
85135
where
86136
M0: ViewModifier, M1: ViewModifier, M2: ViewModifier, M3: ViewModifier, M4: ViewModifier,
87137
M5: ViewModifier, M6: ViewModifier, M7: ViewModifier, M8: ViewModifier, M9: ViewModifier
@@ -90,23 +140,65 @@ import SwiftUI
90140
.concat(m9)
91141
}
92142

93-
/// Provides support for “if” statements in multi-statement closures, producing conditional content for the “then” branch.
94-
public static func buildEither<Modifier>(first left: Modifier) -> some ViewModifier
95-
where Modifier: ViewModifier {
96-
left
143+
/// Provides support for “if” statements in multi-statement closures,
144+
/// producing an optional modifier that is visible only when the condition
145+
/// evaluates to `true`.
146+
public static func buildOptional<Modifier: ViewModifier>(_ modifier: Modifier?)
147+
-> OptionalModifier<Modifier>
148+
{
149+
.init(modifier: modifier)
97150
}
98151

99-
/// Provides support for “if-else” statements in multi-statement closures, producing conditional content for the “else” branch.
100-
public static func buildEither<Modifier>(second right: Modifier) -> some ViewModifier
101-
where Modifier: ViewModifier {
102-
right
152+
/// Provides support for "if" statements in multi-statement closures,
153+
/// producing conditional content for the "then" branch.
154+
public static func buildEither<TrueModifier, FalseModifier>(first left: TrueModifier)
155+
-> ConditionalViewModifier<TrueModifier, FalseModifier>
156+
where TrueModifier: ViewModifier, FalseModifier: ViewModifier {
157+
.trueModifier(left)
103158
}
104159

105-
/// Provides support for “if” statements with #available() clauses in multi-statement closures,
106-
/// producing conditional content for the “then” branch, i.e. the conditionally-available branch.
160+
/// Provides support for "if-else" statements in multi-statement closures,
161+
/// producing conditional content for the "else" branch.
162+
public static func buildEither<TrueModifier, FalseModifier>(second right: FalseModifier)
163+
-> ConditionalViewModifier<TrueModifier, FalseModifier>
164+
where TrueModifier: ViewModifier, FalseModifier: ViewModifier {
165+
.falseModifier(right)
166+
}
167+
168+
/// Provides support for "if" statements with `#available()` clauses in
169+
/// multi-statement closures, producing conditional content for the "then"
170+
/// branch, i.e. the conditionally-available branch.
107171
public static func buildLimitedAvailability<Modifier>(_ modifier: Modifier)
108-
-> some ViewModifier where Modifier: ViewModifier
172+
-> Modifier where Modifier: ViewModifier
109173
{
110174
modifier
111175
}
112176
}
177+
178+
public enum ConditionalViewModifier<TrueModifier: ViewModifier, FalseModifier: ViewModifier>:
179+
ViewModifier
180+
{
181+
case trueModifier(TrueModifier)
182+
case falseModifier(FalseModifier)
183+
184+
public func body(content: Content) -> some View {
185+
switch self {
186+
case let .trueModifier(modifier):
187+
content.modifier(modifier)
188+
case let .falseModifier(modifier):
189+
content.modifier(modifier)
190+
}
191+
}
192+
}
193+
194+
public struct OptionalModifier<Modifier: ViewModifier>: ViewModifier {
195+
let modifier: Modifier?
196+
197+
public func body(content: Content) -> some View {
198+
if let modifier = modifier {
199+
content.modifier(modifier)
200+
} else {
201+
content
202+
}
203+
}
204+
}

Sources/ViewModifiersViewModifier.swift

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)