-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Part of #51.
- Loading branch information
Showing
11 changed files
with
238 additions
and
65 deletions.
There are no files selected for viewing
12 changes: 12 additions & 0 deletions
12
Sources/Slipstream/Documentation.docc/Views/TailwindCSS/Margin.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# Margin | ||
|
||
## Topics | ||
|
||
### Modifiers | ||
|
||
- ``View/margin(_:_:)`` | ||
|
||
### Enumerations | ||
|
||
- ``Edge`` | ||
- ``MarginValue`` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
105 changes: 105 additions & 0 deletions
105
Sources/Slipstream/TailwindCSS/Spacing/View+margin.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
/// A struct representing a margin value for layout purposes, with support | ||
/// for both numerical values and the "auto" value. | ||
@available(iOS 17.0, macOS 14.0, *) | ||
public struct MarginValue { | ||
/// A static instance representing the "auto" margin value. | ||
public static let auto = MarginValue(.auto) | ||
|
||
fileprivate init(integerLiteral value: Int) { | ||
self.storage = .rawValue(Double(value)) | ||
} | ||
|
||
fileprivate init(floatLiteral value: Double) { | ||
self.storage = .rawValue(value) | ||
} | ||
|
||
fileprivate init(_ value: Storage) { | ||
self.storage = value | ||
} | ||
|
||
fileprivate enum Storage { | ||
case rawValue(Double) | ||
case auto | ||
} | ||
fileprivate let storage: Storage | ||
|
||
/// Returns the margin value as the closest Tailwind CSS spacing class. | ||
/// | ||
/// - Returns: The Tailwind CSS spacing class string. | ||
fileprivate func toTailwindSpacingClass() -> String { | ||
switch storage { | ||
case .rawValue(let ptLength): | ||
return Edge.pointToTailwindSpacingClass(ptLength: ptLength) | ||
case .auto: | ||
return "auto" | ||
} | ||
} | ||
} | ||
|
||
extension View { | ||
/// Set the margin for specific edges. | ||
/// | ||
/// - Parameters: | ||
/// - edges: The edges to which margin should be applied. | ||
/// - length: The size of the margin to apply, in points. If the margin is exactly between | ||
/// two margin classes, then the smaller margin class will be used. | ||
/// | ||
/// - SeeAlso: Tailwind CSS' [`margin`](https://tailwindcss.com/docs/margin) documentation. | ||
@available(iOS 17.0, macOS 14.0, *) | ||
public func margin(_ edges: Edge.Set, _ length: MarginValue) -> some View { | ||
let spacingClass = length.toTailwindSpacingClass() | ||
var classes = [String]() | ||
|
||
if Edge.Set.all.isSubset(of: edges) { | ||
classes = ["m-" + spacingClass] | ||
} else { | ||
if Edge.Set.horizontal.isSubset(of: edges) { | ||
classes.append("mx-" + spacingClass) | ||
} else { | ||
if edges.contains(.left) { | ||
classes.append("ml-" + spacingClass) | ||
} | ||
if edges.contains(.right) { | ||
classes.append("mr-" + spacingClass) | ||
} | ||
} | ||
if Edge.Set.vertical.isSubset(of: edges) { | ||
classes.append("my-" + spacingClass) | ||
} else { | ||
if edges.contains(.top) { | ||
classes.append("mt-" + spacingClass) | ||
} | ||
if edges.contains(.bottom) { | ||
classes.append("mb-" + spacingClass) | ||
} | ||
} | ||
} | ||
return modifier(ClassModifier(add: classes.joined(separator: " "))) | ||
} | ||
|
||
/// Set the margin for specific edges. | ||
/// | ||
/// - Parameters: | ||
/// - edges: The edges to which margin should be applied. | ||
/// - length: The size of the margin to apply, in points. If the margin is exactly between | ||
/// two margin classes, then the smaller margin class will be used. | ||
/// | ||
/// - SeeAlso: Tailwind CSS' [`margin`](https://tailwindcss.com/docs/margin) documentation. | ||
@available(iOS 17.0, macOS 14.0, *) | ||
public func margin(_ edges: Edge.Set, _ length: Double) -> some View { | ||
margin(edges, MarginValue(floatLiteral: length)) | ||
} | ||
|
||
/// Set the margin for specific edges. | ||
/// | ||
/// - Parameters: | ||
/// - edges: The edges to which margin should be applied. | ||
/// - length: The size of the margin to apply, in points. If the margin is exactly between | ||
/// two margin classes, then the smaller margin class will be used. | ||
/// | ||
/// - SeeAlso: Tailwind CSS' [`margin`](https://tailwindcss.com/docs/margin) documentation. | ||
@available(iOS 17.0, macOS 14.0, *) | ||
public func margin(_ edges: Edge.Set, _ length: Int) -> some View { | ||
margin(edges, MarginValue(integerLiteral: length)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import Testing | ||
import Slipstream | ||
|
||
private struct MarginView: View { | ||
let margins: Int = 32 | ||
var body: some View { | ||
Div { | ||
|
||
} | ||
.margin(.horizontal, margins) | ||
} | ||
} | ||
|
||
struct MarginTests { | ||
@Test func auto() throws { | ||
try #expect(renderHTML(Div {}.margin(.all, .auto)) == #"<div class="m-auto"></div>"#) | ||
try #expect(renderHTML(Div {}.margin(.horizontal, .auto)) == #"<div class="mx-auto"></div>"#) | ||
try #expect(renderHTML(Div {}.margin(.vertical, .auto)) == #"<div class="my-auto"></div>"#) | ||
try #expect(renderHTML(Div {}.margin([.top, .left], .auto)) == #"<div class="ml-auto mt-auto"></div>"#) | ||
|
||
try #expect(renderHTML(Div {}.margin(.top, .auto)) == #"<div class="mt-auto"></div>"#) | ||
try #expect(renderHTML(Div {}.margin(.left, .auto)) == #"<div class="ml-auto"></div>"#) | ||
try #expect(renderHTML(Div {}.margin(.bottom, .auto)) == #"<div class="mb-auto"></div>"#) | ||
try #expect(renderHTML(Div {}.margin(.right, .auto)) == #"<div class="mr-auto"></div>"#) | ||
} | ||
|
||
@Test func marginEdges() throws { | ||
try #expect(renderHTML(Div {}.margin(.all, 16)) == #"<div class="m-4"></div>"#) | ||
try #expect(renderHTML(Div {}.margin(.horizontal, 8)) == #"<div class="mx-2"></div>"#) | ||
try #expect(renderHTML(Div {}.margin(.vertical, 12)) == #"<div class="my-3"></div>"#) | ||
try #expect(renderHTML(Div {}.margin([.top, .left], 24)) == #"<div class="ml-6 mt-6"></div>"#) | ||
|
||
try #expect(renderHTML(Div {}.margin(.top, 0)) == #"<div class="mt-0"></div>"#) | ||
try #expect(renderHTML(Div {}.margin(.left, 4)) == #"<div class="ml-1"></div>"#) | ||
try #expect(renderHTML(Div {}.margin(.bottom, 32)) == #"<div class="mb-8"></div>"#) | ||
try #expect(renderHTML(Div {}.margin(.right, 64)) == #"<div class="mr-16"></div>"#) | ||
} | ||
|
||
@Test func specificMarginSizes() throws { | ||
try #expect(renderHTML(Div {}.margin(.top, 0)) == #"<div class="mt-0"></div>"#) | ||
try #expect(renderHTML(Div {}.margin(.top, 0.5)) == #"<div class="mt-0"></div>"#) | ||
try #expect(renderHTML(Div {}.margin(.top, 1)) == #"<div class="mt-0"></div>"#) | ||
try #expect(renderHTML(Div {}.margin(.top, 2)) == #"<div class="mt-0.5"></div>"#) | ||
try #expect(renderHTML(Div {}.margin(.top, 3)) == #"<div class="mt-0.5"></div>"#) | ||
try #expect(renderHTML(Div {}.margin(.top, 4)) == #"<div class="mt-1"></div>"#) | ||
try #expect(renderHTML(Div {}.margin(.top, 32)) == #"<div class="mt-8"></div>"#) | ||
try #expect(renderHTML(Div {}.margin(.top, 64)) == #"<div class="mt-16"></div>"#) | ||
} | ||
|
||
@Test func repeatedMarginModifications() throws { | ||
try #expect(renderHTML(Div {}.margin(.top, 0).margin(.right, 4)) == #"<div class="mt-0 mr-1"></div>"#) | ||
try #expect(renderHTML(Div {}.margin(.top, 0).margin(.top, 4)) == #"<div class="mt-0 mt-1"></div>"#) | ||
} | ||
} |