Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for if statements. #23

Merged
merged 3 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ conforms to the ``View`` protocol can act as a view in your website.
### Modifying a view

- ``ViewModifier``

### Supporting view types

- ``EmptyView``
17 changes: 17 additions & 0 deletions Sources/Slipstream/Views/Fundamentals/EmptyView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/// A view that doesn't contain any content.
///
/// You will rarely, if ever, need to create an `EmptyView` directly. Instead,
/// `EmptyView` represents the absence of a view.
///
/// Slipstream uses `EmptyView` in situations where a Slipstream view type defines one
/// or more child views with generic parameters, and allows the child views to
/// be absent. When absent, the child view's type in the generic type parameter
/// is `EmptyView`.
@available(iOS 17.0, macOS 14.0, *)
public struct EmptyView: View {
public typealias Content = Never

/// Creates an empty view.
public init() {
}
}
4 changes: 4 additions & 0 deletions Sources/Slipstream/Views/Fundamentals/View.swift
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ extension View where Content == Never {
public var body: Never {
fatalError("body should never be executed when a view has declared its Content as Never")
}

public func render(_ container: Element, environment: EnvironmentValues) throws {
// Do nothing.
}
}

@_documentation(visibility: private)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import SwiftSoup

/// A View created from a for loop of View values.
@_documentation(visibility: private)
@available(iOS 17.0, macOS 14.0, *)
public struct ArrayView: View {
public typealias Content = Never

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import SwiftSoup

/// A View created from an if/else conditional of View values.
@_documentation(visibility: private)
@available(iOS 17.0, macOS 14.0, *)
public struct ConditionalView<T: View, F: View>: View {
enum Condition {
case isTrue(T)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import SwiftSoup

/// A View created from a swift tuple of View values.
@_documentation(visibility: private)
@available(iOS 17.0, macOS 14.0, *)
public struct TupleView<T>: View {
public typealias Content = Never

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,26 @@ public struct ViewBuilder {
return TupleView(value: (repeat each content))
}

/// An if statement.
///
/// An example:
///
/// ```swift
/// var body: some View {
/// if true {
/// Text("true")
/// }
/// }
/// ```
public static func buildOptional<Content>(_ component: Content?) -> ConditionalView<Content, EmptyView>
where Content: View {
if let component {
return ConditionalView(condition: .isTrue(component))
} else {
return ConditionalView(condition: .isFalse(EmptyView()))
}
}

/// An if/else statement, when the condition returns true.
///
/// An example:
Expand Down
22 changes: 18 additions & 4 deletions Tests/SlipstreamTests/ViewBuilderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ private struct TupleBlockView: View {
}
}

private struct ConditionalBlockView: View {
private struct IfElseBlockView: View {
let bool: Bool
var body: some View {
if bool {
Expand All @@ -26,6 +26,15 @@ private struct ConditionalBlockView: View {
}
}

private struct IfBlockView: View {
let bool: Bool
var body: some View {
if bool {
Text("true")
}
}
}

private struct ArrayBlockView: View {
var body: some View {
for i in 1...3 {
Expand All @@ -43,9 +52,14 @@ struct ViewBuilderTests {
try #expect(renderHTML(TupleBlockView()) == "Hello, world!")
}

@Test func conditionalBlock() throws {
try #expect(renderHTML(ConditionalBlockView(bool: true)) == "true")
try #expect(renderHTML(ConditionalBlockView(bool: false)) == "false")
@Test func ifElseBlock() throws {
try #expect(renderHTML(IfElseBlockView(bool: true)) == "true")
try #expect(renderHTML(IfElseBlockView(bool: false)) == "false")
}

@Test func ifBlock() throws {
try #expect(renderHTML(IfBlockView(bool: true)) == "true")
try #expect(renderHTML(IfBlockView(bool: false)) == "")
}

@Test func arrayBlock() throws {
Expand Down