Skip to content

Commit

Permalink
Add support for upper-bound breakpoint.
Browse files Browse the repository at this point in the history
  • Loading branch information
jverkoey committed Aug 5, 2024
1 parent 85f649f commit 42dcdf5
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 28 deletions.
26 changes: 20 additions & 6 deletions Sources/Slipstream/TailwindCSS/Breakpoint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,24 @@
///
/// - SeeAlso: Tailwind CSS' [`responsive design`](https://tailwindcss.com/docs/responsive-design) documentation.
@available(iOS 17.0, macOS 14.0, *)
public enum Breakpoint: String {
case small = "sm"
case medium = "md"
case large = "lg"
case extraLarge = "xl"
case extraExtraLarge = "2xl"
public enum Breakpoint: Int, Comparable {
case small
case medium
case large
case extraLarge
case extraExtraLarge

var asTailwindClass: String {
switch self {
case .small: return "sm"
case .medium: return "md"
case .large: return "lg"
case .extraLarge: return "xl"
case .extraExtraLarge: return "2xl"
}
}

public static func < (lhs: Breakpoint, rhs: Breakpoint) -> Bool {
lhs.rawValue < rhs.rawValue
}
}
43 changes: 31 additions & 12 deletions Sources/Slipstream/TailwindCSS/Condition.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,32 @@
public struct Condition {
/// Creates a Condition with a set of states.
public init(state: State.Set) {
self.minBreakpoint = nil
self.startingAtBreakpoint = nil
self.endingBeforeBreakpoint = nil
self.state = state
}

/// Creates a Condition with a minimum breakpoint.
public init(minBreakpoint: Breakpoint) {
self.minBreakpoint = minBreakpoint
/// Creates a Condition that starts at a given breakpoint.
public init(startingAt breakpoint: Breakpoint) {
self.startingAtBreakpoint = breakpoint
self.endingBeforeBreakpoint = nil
self.state = nil
}

/// Creates a Condition with a minimum breakpoint and set of states.
public init(minBreakpoint: Breakpoint, state: State.Set) {
self.minBreakpoint = minBreakpoint
/// Creates a Condition that starts at a given breakpoint and set of states.
public init(startingAt breakpoint: Breakpoint, state: State.Set) {
self.startingAtBreakpoint = breakpoint
self.endingBeforeBreakpoint = nil
self.state = state
}

/// Creates a Condition that applies within the range of breakpoints.
public init(within range: Range<Breakpoint>) {
self.startingAtBreakpoint = range.lowerBound
self.endingBeforeBreakpoint = range.upperBound
self.state = nil
}

/// A convenience condition representing dark mode.
public static let dark = Condition(state: .dark)

Expand All @@ -32,14 +42,22 @@ public struct Condition {
public static let active = Condition(state: .active)

/// A convenience condition representing a minimum breakpoint.
public static func minBreakpoint(_ minBreakpoint: Breakpoint) -> Self {
return Condition(minBreakpoint: minBreakpoint)
public static func startingAt(_ breakpoint: Breakpoint) -> Self {
return Condition(startingAt: breakpoint)
}

/// A convenience condition representing a minimum breakpoint.
public static func within(_ range: Range<Breakpoint>) -> Self {
return Condition(within: range)
}

var tailwindClassModifiers: String {
var modifiers: [String] = []
if let minBreakpoint {
modifiers.append(minBreakpoint.rawValue)
if let startingAtBreakpoint {
modifiers.append(startingAtBreakpoint.asTailwindClass)
}
if let endingBeforeBreakpoint {
modifiers.append("max-" + endingBeforeBreakpoint.asTailwindClass)
}
if let set = state, set.rawValue != 0 {
modifiers.append(contentsOf: State.allCases
Expand All @@ -51,6 +69,7 @@ public struct Condition {
return modifiers.joined(separator: ":")
}

private let minBreakpoint: Breakpoint?
private let startingAtBreakpoint: Breakpoint?
private let endingBeforeBreakpoint: Breakpoint?
private let state: State.Set?
}
2 changes: 1 addition & 1 deletion Tests/SlipstreamTests/Sites/CatalogSiteTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ private struct CatalogSite: View {
.border(.black, width: 4, edges: .bottom)
.backgroundImage(URL(string: "/logo.svg"), size: .size(width: 50, height: 100), repeat: .no)
.textColor(.red, darkness: 800, condition: .dark)
.padding(.horizontal, 48, condition: .minBreakpoint(.large))
.padding(.horizontal, 48, condition: .startingAt(.large))
.animation(.easeInOut(duration: 0.3))
}
.id("root")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ struct FlexDirectionTests {
}

@Test func conditions() throws {
try #expect(renderHTML(Div {}.flexDirection(.y, condition: .init(minBreakpoint: .medium))) == #"<div class="md:flex-col"></div>"#)
try #expect(renderHTML(Div {}.flexDirection(.y, condition: .init(startingAt: .medium))) == #"<div class="md:flex-col"></div>"#)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ struct DisplayTests {
Div {
}.display(
.block,
condition: .init(minBreakpoint: .medium)
condition: .init(startingAt: .medium)
)) == #"<div class="md:block"></div>"#
)
}
Expand Down
7 changes: 2 additions & 5 deletions Tests/SlipstreamTests/TailwindCSS/Spacing/MarginTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,7 @@ struct MarginTests {
}

@Test func condition() throws {
try #expect(
renderHTML(
Div {
}.margin(8, condition: .init(minBreakpoint: .large))) == #"<div class="lg:m-2"></div>"#
)
try #expect(renderHTML(Div {}.margin(8, condition: .init(startingAt: .large))) == #"<div class="lg:m-2"></div>"#)
try #expect(renderHTML(Div {}.margin(8, condition: .within(Breakpoint.small..<Breakpoint.large))) == #"<div class="sm:max-lg:m-2"></div>"#)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ struct PaddingTests {
}.padding(.top, 0).padding(
.right,
4,
condition: .init(minBreakpoint: .medium)
condition: .init(startingAt: .medium)
)) == #"<div class="pt-0 md:pr-1"></div>"#
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ struct TextAlignmentTests {
Div {
}.textAlignment(
.left,
condition: .init(minBreakpoint: .extraExtraLarge)
condition: .init(startingAt: .extraExtraLarge)
)) == #"<div class="2xl:text-left"></div>"#
)
}
Expand Down

0 comments on commit 42dcdf5

Please sign in to comment.