From 40d81f8260ce881afa258c8b612dddd2a062e824 Mon Sep 17 00:00:00 2001 From: Jeff Verkoeyen Date: Mon, 5 Aug 2024 16:12:04 -0400 Subject: [PATCH] Add cornerRadius modifier. Part of https://github.com/jverkoey/slipstream/issues/51. --- .../Documentation.docc/Slipstream.md | 2 +- .../Borders/Borders-CornerRadius.md | 15 ++++++ ...SS-Classes.md => TailwindCSS-Utilities.md} | 5 +- .../Borders/View+cornerRadius.swift | 53 +++++++++++++++++++ .../Borders/CornerRadiusTests.swift | 32 +++++++++++ 5 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 Sources/Slipstream/Documentation.docc/TailwindCSS/Borders/Borders-CornerRadius.md rename Sources/Slipstream/Documentation.docc/TailwindCSS/{TailwindCSS-Classes.md => TailwindCSS-Utilities.md} (88%) create mode 100644 Sources/Slipstream/TailwindCSS/Borders/View+cornerRadius.swift create mode 100644 Tests/SlipstreamTests/TailwindCSS/Borders/CornerRadiusTests.swift diff --git a/Sources/Slipstream/Documentation.docc/Slipstream.md b/Sources/Slipstream/Documentation.docc/Slipstream.md index 8f7d91b..d48c0a5 100644 --- a/Sources/Slipstream/Documentation.docc/Slipstream.md +++ b/Sources/Slipstream/Documentation.docc/Slipstream.md @@ -66,7 +66,7 @@ print(try renderHTML(HelloWorld())) ### Tailwind CSS - -- +- ### Markdown diff --git a/Sources/Slipstream/Documentation.docc/TailwindCSS/Borders/Borders-CornerRadius.md b/Sources/Slipstream/Documentation.docc/TailwindCSS/Borders/Borders-CornerRadius.md new file mode 100644 index 0000000..be35556 --- /dev/null +++ b/Sources/Slipstream/Documentation.docc/TailwindCSS/Borders/Borders-CornerRadius.md @@ -0,0 +1,15 @@ +# Corner radius + +Utilities for controlling the corner radius of a view. + +## Topics + +### Modifiers + +- ``View/cornerRadius(_:condition:)-n56e`` +- ``View/cornerRadius(_:condition:)-6tvub`` + +### Supporting types + +- ``CornerRadius`` + diff --git a/Sources/Slipstream/Documentation.docc/TailwindCSS/TailwindCSS-Classes.md b/Sources/Slipstream/Documentation.docc/TailwindCSS/TailwindCSS-Utilities.md similarity index 88% rename from Sources/Slipstream/Documentation.docc/TailwindCSS/TailwindCSS-Classes.md rename to Sources/Slipstream/Documentation.docc/TailwindCSS/TailwindCSS-Utilities.md index 62b7b6b..0ffbf97 100644 --- a/Sources/Slipstream/Documentation.docc/TailwindCSS/TailwindCSS-Classes.md +++ b/Sources/Slipstream/Documentation.docc/TailwindCSS/TailwindCSS-Utilities.md @@ -1,6 +1,6 @@ -# Classes +# Utilities -Slipstream implementations of Tailwind CSS's classes. +Slipstream implementations of Tailwind CSS's utility classes. ## Topics @@ -45,6 +45,7 @@ Slipstream implementations of Tailwind CSS's classes. ### Borders - +- ### Transitions and animations diff --git a/Sources/Slipstream/TailwindCSS/Borders/View+cornerRadius.swift b/Sources/Slipstream/TailwindCSS/Borders/View+cornerRadius.swift new file mode 100644 index 0000000..c6e0b4e --- /dev/null +++ b/Sources/Slipstream/TailwindCSS/Borders/View+cornerRadius.swift @@ -0,0 +1,53 @@ +/// Constants that specify the corner radius of the view. +/// +/// - SeeAlso: Tailwind CSS' [border radius](https://tailwindcss.com/docs/border-radius) documentation. +public enum CornerRadius: String { + case none = "-none" + case small = "-sm" + case base = "" + case medium = "-md" + case large = "-lg" + case extraLarge = "-xl" + case extraExtraLarge = "-2xl" + case extraExtraExtraLarge = "-3xl" + case full = "-full" +} + +extension View { + /// Changes the corner radius of the view. + /// + /// - SeeAlso: Tailwind CSS' [border radius](https://tailwindcss.com/docs/border-radius) documentation. + @available(iOS 17.0, macOS 14.0, *) + public func cornerRadius(_ radius: CornerRadius, condition: Condition? = nil) -> some View { + return self.modifier(TailwindClassModifier(add: "rounded" + radius.rawValue, condition: condition)) + } + + /// Set the font corner radius to the closest equivalent Tailwind CSS radius size. + /// + /// - Parameters: + /// - ptSize: A corner size in `pt` units. The closest Tailwind corner + /// size class that matches this point size will be used. If the size is exactly between + /// two classes, then the smaller of the two will be used. + /// - condition: An optional Tailwind condition defining when to apply this modifier. + /// + /// - SeeAlso: Tailwind CSS' [`font-size`](https://tailwindcss.com/docs/font-size) documentation. + @available(iOS 17.0, macOS 14.0, *) + public func cornerRadius(_ ptSize: Int, condition: Condition? = nil) -> some View { + return cornerRadius(closestTailwindCornerRadius(ptSize: ptSize), condition: condition) + } + + private func closestTailwindCornerRadius(ptSize: Int) -> CornerRadius { + let mapping: [(cornerRadius: CornerRadius, ptSize: Int)] = [ + (.none, 0), + (.small, 2), // 0.125rem + (.base, 4), // 0.25rem + (.medium, 6), // 0.375rem + (.large, 8), // 0.5rem + (.extraLarge, 12), // 0.75rem + (.extraExtraLarge, 16), // 1rem + (.extraExtraExtraLarge, 24), // 1.5rem + ] + let closest = mapping.min { abs($0.ptSize - ptSize) < abs($1.ptSize - ptSize) } + return closest?.cornerRadius ?? .none + } +} diff --git a/Tests/SlipstreamTests/TailwindCSS/Borders/CornerRadiusTests.swift b/Tests/SlipstreamTests/TailwindCSS/Borders/CornerRadiusTests.swift new file mode 100644 index 0000000..6f0a666 --- /dev/null +++ b/Tests/SlipstreamTests/TailwindCSS/Borders/CornerRadiusTests.swift @@ -0,0 +1,32 @@ +import Testing +import Slipstream + +struct CornerRadiusTests { + @Test func enumeration() throws { + try #expect(renderHTML(Div {}.cornerRadius(.none)) == #"
"#) + try #expect(renderHTML(Div {}.cornerRadius(.small)) == #"
"#) + try #expect(renderHTML(Div {}.cornerRadius(.base)) == #"
"#) + try #expect(renderHTML(Div {}.cornerRadius(.medium)) == #"
"#) + try #expect(renderHTML(Div {}.cornerRadius(.large)) == #"
"#) + try #expect(renderHTML(Div {}.cornerRadius(.extraLarge)) == #"
"#) + try #expect(renderHTML(Div {}.cornerRadius(.extraExtraLarge)) == #"
"#) + try #expect(renderHTML(Div {}.cornerRadius(.extraExtraExtraLarge)) == #"
"#) + try #expect(renderHTML(Div {}.cornerRadius(.full)) == #"
"#) + } + + @Test func points() throws { + try #expect(renderHTML(Div {}.cornerRadius(0)) == #"
"#) + try #expect(renderHTML(Div {}.cornerRadius(1)) == #"
"#) + try #expect(renderHTML(Div {}.cornerRadius(2)) == #"
"#) + try #expect(renderHTML(Div {}.cornerRadius(3)) == #"
"#) + try #expect(renderHTML(Div {}.cornerRadius(4)) == #"
"#) + try #expect(renderHTML(Div {}.cornerRadius(5)) == #"
"#) + try #expect(renderHTML(Div {}.cornerRadius(6)) == #"
"#) + try #expect(renderHTML(Div {}.cornerRadius(7)) == #"
"#) + try #expect(renderHTML(Div {}.cornerRadius(8)) == #"
"#) + try #expect(renderHTML(Div {}.cornerRadius(9)) == #"
"#) + try #expect(renderHTML(Div {}.cornerRadius(10)) == #"
"#) + try #expect(renderHTML(Div {}.cornerRadius(11)) == #"
"#) + try #expect(renderHTML(Div {}.cornerRadius(12)) == #"
"#) + } +}