Skip to content

Commit

Permalink
Add Image view. (#88)
Browse files Browse the repository at this point in the history
Part of #25.
  • Loading branch information
jverkoey authored Aug 5, 2024
1 parent 7eb3807 commit 35dec5e
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# ``Image``

## Topics

### Required accessibility modifiers

- ``View/accessibilityLabel(_:)``
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@
- ``View/classNames(_:)``
- ``View/id(_:)``
- ``View/language(_:)``

### Images

- ``View/accessibilityLabel(_:)``
7 changes: 7 additions & 0 deletions Sources/Slipstream/Documentation.docc/Views/W3C/W3CViews.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,15 @@ The complete W3C HTML elements standard can be found [here](https://html.spec.wh
### Text-level semantics

- ``Linebreak``

### Links

- ``Link``

### Embedded content

- ``Image``

### Scripting

- <doc:Script>
41 changes: 23 additions & 18 deletions Sources/Slipstream/Markdown/MarkdownText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,31 @@ import SwiftSoup
/// ```swift
/// import Markdown
/// import Slipstream
///
/// MarkdownText("""
/// ## Hello world
///
/// This is some markdown content.
/// """
/// ) { node, context in
/// switch node {
/// case let text as Markdown.Text:
/// Slipstream.Text(text.string)
/// case let heading as Markdown.Heading:
/// Slipstream.Heading(level: heading.level) {
/// context.recurse()
/// }
/// case is Markdown.Paragraph:
/// Slipstream.Paragraph {
/// context.recurse()
/// struct Article: View {
/// private let text: String
///
/// init(_ text: String) {
/// self.text = text
/// }
///
/// var body: some View {
/// MarkdownText(text) { node, context in
/// switch node {
/// case let text as Markdown.Text:
/// Slipstream.Text(text.string)
/// case let heading as Markdown.Heading:
/// Slipstream.Heading(level: heading.level) {
/// context.recurse()
/// }
/// case is Markdown.Paragraph:
/// Slipstream.Paragraph {
/// context.recurse()
/// }
/// default:
/// context.recurse()
/// }
/// }
/// default:
/// context.recurse()
/// }
/// }
/// ```
Expand Down
13 changes: 13 additions & 0 deletions Sources/Slipstream/W3C/Attributes/View+accessibilityLabel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
extension View {
/// Provides equivalent content for those who cannot process images or
/// who have image loading disabled.
///
/// - SeeAlso: W3C [alt](https://html.spec.whatwg.org/multipage/images.html#alt) guidance.
///
/// ## See Also
///
/// - ``Image``
public func accessibilityLabel(_ string: String) -> some View {
modifier(AttributeModifier("alt", value: string))
}
}
41 changes: 41 additions & 0 deletions Sources/Slipstream/W3C/Elements/EmbeddedContent/Image.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import Foundation

import SwiftSoup

/// A view that displays an image.
///
/// ```swift
/// struct MySiteContent: View {
/// var body: some View {
/// Body {
/// Image(URL(string: "/logo.png"))
/// .accessibilityLabel("My awesome site logo")
/// }
/// }
/// }
/// ```
///
/// - SeeAlso: W3C [`img`](https://html.spec.whatwg.org/multipage/embedded-content.html#the-img-element) specification.
/// - SeeAlso: W3C [requirements for providing text to act as an alternative for images](https://html.spec.whatwg.org/multipage/images.html#alt).
///
/// ## See Also
///
/// - ``View/accessibilityLabel(_:)``
@available(iOS 17.0, macOS 14.0, *)
public struct Image: View {
/// Creates a Stylesheet view.
public init(_ url: URL?) {
self.url = url
}

@_documentation(visibility: private)
public func render(_ container: Element, environment: EnvironmentValues) throws {
guard let url else {
return
}
let element = try container.appendElement("img")
try element.attr("src", url.absoluteString)
}

private let url: URL?
}
4 changes: 4 additions & 0 deletions Tests/SlipstreamTests/Sites/CatalogSiteTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ private struct CatalogSite: View {
.padding(.horizontal, 48, condition: .startingAt(.large) + .hover)
.animation(.easeInOut(duration: 0.3))

Image(URL(string: "/logo.png"))
.accessibilityLabel("Site logo")

Script(URL(string: "/main.js"), executionMode: .async)
Script("""
alert("Hello, world!");
Expand Down Expand Up @@ -104,6 +107,7 @@ struct CatalogSiteTests {
<h2>Generic heading 2</h2>
</div>
</div>
<img src="/logo.png" alt="Site logo" />
<script src="/main.js" async></script>
<script>alert("Hello, world!");</script>
</body>
Expand Down
18 changes: 18 additions & 0 deletions Tests/SlipstreamTests/W3C/ImageTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Foundation
import Testing

import Slipstream

struct ImageTests {
@Test func nilURL() throws {
try #expect(renderHTML(Image(nil)) == "")
}

@Test func url() throws {
try #expect(renderHTML(Image(URL(string: "/logo.png"))) == #"<img src="/logo.png" />"#)
}

@Test func accessibilityLabel() throws {
try #expect(renderHTML(Image(URL(string: "/logo.png")).accessibilityLabel("My logo")) == #"<img src="/logo.png" alt="My logo" />"#)
}
}

0 comments on commit 35dec5e

Please sign in to comment.