From a355b5e79743ab8788c7bb016e1dd853064540ac Mon Sep 17 00:00:00 2001 From: Jeff Verkoeyen Date: Sat, 14 Sep 2024 16:34:55 -0700 Subject: [PATCH] Add opacity modifier. Part of https://github.com/jverkoey/slipstream/issues/51. --- .../SlipstreamForTailwindCSSDevelopers.md | 2 +- .../TailwindCSS/TailwindCSS-Utilities.md | 1 + .../TailwindCSS/Effects/View+opacity.swift | 45 +++++++++++++++++++ .../TailwindCSS/Effects/OpacityTests.swift | 29 ++++++++++++ 4 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 Sources/Slipstream/TailwindCSS/Effects/View+opacity.swift create mode 100644 Tests/SlipstreamTests/TailwindCSS/Effects/OpacityTests.swift diff --git a/Sources/Slipstream/Documentation.docc/Guides/SlipstreamForTailwindCSSDevelopers.md b/Sources/Slipstream/Documentation.docc/Guides/SlipstreamForTailwindCSSDevelopers.md index e2806f5..6b050c1 100644 --- a/Sources/Slipstream/Documentation.docc/Guides/SlipstreamForTailwindCSSDevelopers.md +++ b/Sources/Slipstream/Documentation.docc/Guides/SlipstreamForTailwindCSSDevelopers.md @@ -171,7 +171,7 @@ Tailwind utility | Slipstream modifier :----------------|:------------------- [Box Shadow](https://tailwindcss.com/docs/box-shadow) | ``View/shadow(color:radius:condition:)`` [Box Shadow Color](https://tailwindcss.com/docs/box-shadow-color) | ``View/shadow(color:radius:condition:) -[Opacity](https://tailwindcss.com/docs/opacity) | [Not implemented yet](https://github.com/jverkoey/slipstream/issues/51) +[Opacity](https://tailwindcss.com/docs/opacity) | ``View/opacity(_:condition:)`` [Mix Blend Mode](https://tailwindcss.com/docs/mix-blend-mode) | [Not implemented yet](https://github.com/jverkoey/slipstream/issues/51) [Background Blend Mode](https://tailwindcss.com/docs/background-blend-mode) | [Not implemented yet](https://github.com/jverkoey/slipstream/issues/51) diff --git a/Sources/Slipstream/Documentation.docc/TailwindCSS/TailwindCSS-Utilities.md b/Sources/Slipstream/Documentation.docc/TailwindCSS/TailwindCSS-Utilities.md index 675f0d1..9437108 100644 --- a/Sources/Slipstream/Documentation.docc/TailwindCSS/TailwindCSS-Utilities.md +++ b/Sources/Slipstream/Documentation.docc/TailwindCSS/TailwindCSS-Utilities.md @@ -56,6 +56,7 @@ Slipstream implementations of Tailwind CSS's utility classes. ### Effects - +- ``View/opacity(_:condition:)`` ### Filters diff --git a/Sources/Slipstream/TailwindCSS/Effects/View+opacity.swift b/Sources/Slipstream/TailwindCSS/Effects/View+opacity.swift new file mode 100644 index 0000000..06b20a4 --- /dev/null +++ b/Sources/Slipstream/TailwindCSS/Effects/View+opacity.swift @@ -0,0 +1,45 @@ +extension View { + /// Sets the opacity of the view. + /// + /// - SeeAlso: Tailwind CSS' [opacity](https://tailwindcss.com/docs/opacity) documentation. + @available(iOS 17.0, macOS 14.0, *) + public func opacity(_ opacity: Double, condition: Condition? = nil + ) -> some View { + return modifier(TailwindClassModifier( + add: "opacity-" + Self.opacityToTailwindOpacityClass(opacity: opacity), + condition: condition) + ) + } + + /// Maps an opacity to the closest Tailwind CSS opacity class. + /// + /// - Parameter opacity: The opacity to be mapped. + /// - Returns: The Tailwind CSS opacity class. + private static func opacityToTailwindOpacityClass(opacity: Double) -> String { + let mapping: [(name: String, opacity: Double)] = [ + ("0", 0.00), + ("5", 0.05), + ("10", 0.10), + ("15", 0.15), + ("20", 0.20), + ("25", 0.25), + ("30", 0.30), + ("35", 0.35), + ("40", 0.40), + ("45", 0.45), + ("50", 0.50), + ("55", 0.55), + ("60", 0.60), + ("65", 0.65), + ("70", 0.70), + ("75", 0.75), + ("80", 0.80), + ("85", 0.85), + ("90", 0.90), + ("95", 0.95), + ("100", 1.00), + ] + let closestClass = mapping.min { abs($0.opacity - opacity) < abs($1.opacity - opacity) } + return closestClass?.name ?? "0" + } +} diff --git a/Tests/SlipstreamTests/TailwindCSS/Effects/OpacityTests.swift b/Tests/SlipstreamTests/TailwindCSS/Effects/OpacityTests.swift new file mode 100644 index 0000000..8419234 --- /dev/null +++ b/Tests/SlipstreamTests/TailwindCSS/Effects/OpacityTests.swift @@ -0,0 +1,29 @@ +import Testing + +import Slipstream + +struct OpacityTests { + @Test func opacities() throws { + try #expect(renderHTML(Div {}.opacity(0.00)) == #"
"#) + try #expect(renderHTML(Div {}.opacity(0.05)) == #"
"#) + try #expect(renderHTML(Div {}.opacity(0.10)) == #"
"#) + try #expect(renderHTML(Div {}.opacity(0.15)) == #"
"#) + try #expect(renderHTML(Div {}.opacity(0.20)) == #"
"#) + try #expect(renderHTML(Div {}.opacity(0.25)) == #"
"#) + try #expect(renderHTML(Div {}.opacity(0.30)) == #"
"#) + try #expect(renderHTML(Div {}.opacity(0.35)) == #"
"#) + try #expect(renderHTML(Div {}.opacity(0.40)) == #"
"#) + try #expect(renderHTML(Div {}.opacity(0.45)) == #"
"#) + try #expect(renderHTML(Div {}.opacity(0.50)) == #"
"#) + try #expect(renderHTML(Div {}.opacity(0.55)) == #"
"#) + try #expect(renderHTML(Div {}.opacity(0.60)) == #"
"#) + try #expect(renderHTML(Div {}.opacity(0.65)) == #"
"#) + try #expect(renderHTML(Div {}.opacity(0.70)) == #"
"#) + try #expect(renderHTML(Div {}.opacity(0.75)) == #"
"#) + try #expect(renderHTML(Div {}.opacity(0.80)) == #"
"#) + try #expect(renderHTML(Div {}.opacity(0.85)) == #"
"#) + try #expect(renderHTML(Div {}.opacity(0.90)) == #"
"#) + try #expect(renderHTML(Div {}.opacity(0.95)) == #"
"#) + try #expect(renderHTML(Div {}.opacity(1.00)) == #"
"#) + } +}