Skip to content

Latest commit

 

History

History
194 lines (144 loc) · 4.84 KB

File metadata and controls

194 lines (144 loc) · 4.84 KB
Conditionals Icon

Conditionals

Clean, composable conditional modifier APIs for SwiftUI OS availability checks.

Swift 6.0+ iOS 16+ macOS 13+ tvOS 16+ watchOS 9+ visionOS 1+

Overview

  • Fluent API for OS version-gated modifiers instead of nested #available checks
  • View, ToolbarContent, and ToolbarItemPlacement extensions out of the box
  • Generic conditional() functions for any type
  • Conditional protocol to add conditional support to custom types
  • OSVersion helpers for clean version checks (OSVersion.iOS(17))

Important: Conditionals is for static conditions (OS versions, compile-time checks). For runtime state that changes, use standard SwiftUI patterns (if, ternary, overlay). See When to Use for guidance.

// GOOD - OS version never changes at runtime
.conditional(if: OSVersion.iOS(17)) { view in view.fontDesign(.rounded) }

// BAD - use .foregroundStyle(isActive ? .blue : .gray) instead
.conditional(if: isActive) { view in view.foregroundStyle(.blue) }

Installation

dependencies: [
    .package(url: "https://github.com/aeastr/Conditionals.git", from: "1.0.0")
]
import Conditionals

Usage

OS Version Checks

Apply modifiers based on OS version availability:

Text("Modern UI")
    .conditional { view in
        if #available(iOS 26.0, *) {
            view.glassEffect(.regular, in: .rect(cornerRadius: 12))
        } else {
            view.background(.regularMaterial, in: .rect(cornerRadius: 12))
        }
    }

Simple Conditions

Text("Hello")
    .conditional(if: OSVersion.iOS(17)) { view in
        view.fontDesign(.rounded)
    }

Optional Unwrapping

Text("Hello")
    .conditional(if: optionalColor) { view, color in
        view.foregroundStyle(color)
    }

Toolbar Placement

ToolbarItemGroup(
    placement: .conditional(
        if: OSVersion.iOS(26),
        then: .bottomBar,
        else: .secondaryAction
    )
) {
    Button("Edit") {}
}

With Fallback

Text("Hello")
    .conditional(
        if: OSVersion.iOS(26),
        apply: { $0.fontWeight(.bold) },
        otherwise: { $0.fontWeight(.regular) }
    )

Unless (Negated)

Text("Content")
    .conditional(unless: isCompact) { view in
        view.padding(.horizontal, 40)
    }

Generic Functions

For inline value selection:

Text("Hello")
    .foregroundStyle(
        conditional(if: OSVersion.iOS(17), then: Color.red.gradient, else: Color.red)
    )

Any Type via Protocol

Add conditional support to any type with one line:

extension PresentationDetent: Conditional {}

// Now use it
.presentationDetents([
    .conditional(if: OSVersion.iOS(16), then: .height(300), else: .medium)
])

Customization

OS Version Helpers

OSVersion.iOS(18)       // Check iOS 18+
OSVersion.macOS(14)     // Check macOS 14+
OSVersion.watchOS(10)   // Check watchOS 10+
OSVersion.tvOS(17)      // Check tvOS 17+

OS.is26                 // Quick boolean check for iOS 26+

How It Works

Conditionals wraps the standard #available pattern in a chainable API using @ViewBuilder closures:

// Before: Verbose, breaks the chain
Group {
    if #available(iOS 26.0, *) {
        Text("Hello").glassEffect(.regular, in: .rect(cornerRadius: 12))
    } else {
        Text("Hello").background(.regularMaterial, in: .rect(cornerRadius: 12))
    }
}

// After: Clean and chainable
Text("Hello")
    .conditional { view in
        if #available(iOS 26.0, *) {
            view.glassEffect(.regular, in: .rect(cornerRadius: 12))
        } else {
            view.background(.regularMaterial, in: .rect(cornerRadius: 12))
        }
    }

For iOS 26's glass effects specifically, check out UniversalGlass.

Contributing

Contributions welcome. See the Contributing Guide for details.

License

MIT. See LICENSE for details.