Turbocharger aims accelerate SwiftUI development by providing commonly desired views and view modifiers

Turbocharger

Turbocharger aims accelerate SwiftUI development by providing commonly desired views and view modifiers. Highlights include an AdaptiveStack to better support dynamic type and WeightedVStack/WeightedHStack for relational layouts.

Built for performance and backwards compatibility using Engine

Requirements

  • Deployment target: iOS 13.0, macOS 10.15, tvOS 13.0, or watchOS 6.0
  • Xcode 14.1+

Installation

Xcode Projects

Select File -> Swift Packages -> Add Package Dependency and enter https://github.com/nathantannar4/Turbocharger.

Swift Package Manager Projects

You can add Turbocharger as a package dependency in your Package.swift file:

let package = Package(
    //...
    dependencies: [
        .package(url: "https://github.com/nathantannar4/Turbocharger"),
    ],
    targets: [
        .target(
            name: "YourPackageTarget",
            dependencies: [
                .product(name: "Turbocharger", package: "Turbocharger"),
            ],
            //...
        ),
        //...
    ],
    //...
)

Introduction to Turbocharger

Turbocharger was started with the two goals. 1) To expand the standard API that SwiftUI provides to what many would commonly desired or need; and 2) To demonstrate how to use Engine to make reusable components that are backwards compatible.

LabeledView

/// The ``ViewStyle`` for ``LabeledView``
public protocol LabeledViewStyle: ViewStyle where Configuration == LabeledViewStyleConfiguration {

}

/// The ``ViewStyledView.Configuration`` for ``LabeledView``
public struct LabeledViewStyleConfiguration {
    /// A type-erased label of a ``LabeledView``
    public struct Label: ViewAlias { }
    public var label: Label

    /// A type-erased content of a ``LabeledView``
    public struct Content: ViewAlias { }
    public var content: Content
}

/// A backwards compatible port of `LabeledContent`
public struct LabeledView<Label: View, Content: View>: View {

    public init(
        @ViewBuilder content: () -> Content,
        @ViewBuilder label: () -> Label
    )
}

HVStack/AdaptiveStack

/// A view that arranges its subviews in a vertical or horizontal line.
@frozen
public struct HVStack<Content: View>: View {

    public init(
        axis: Axis,
        alignment: Alignment = .center,
        spacing: CGFloat? = nil,
        @ViewBuilder content: () -> Content
    )
}
    
/// A view that arranges its subviews in a horizontal line when such a layout
/// would fit the available space. If there is not enough space, it arranges it's subviews
/// in a vertical line.
@frozen
public struct AdaptiveStack<Content: View>: View {

    public init(
        alignment: Alignment = .center,
        spacing: CGFloat? = nil,
        @ViewBuilder content: () -> Content
    )
}

WeightedHStack/WeightedVStack

/// A view that arranges its subviews in a horizontal line a width
/// that is relative to its `LayoutWeightPriority`.
///
/// By default, all subviews will be arranged with equal width.
///
@frozen
public struct WeightedHStack<Content: View>: View {

    public init(
        alignment: VerticalAlignment = .center,
        spacing: CGFloat? = nil,
        @ViewBuilder content: () -> Content
    )
}

/// A view that arranges its subviews in a vertical line a height
/// that is relative to its `LayoutWeightPriority`.
///
/// By default, all subviews will be arranged with equal height.
///
@frozen
public struct WeightedVStack<Content: View>: View {

    public init(
        alignment: HorizontalAlignment = .center,
        spacing: CGFloat? = nil,
        @ViewBuilder content: () -> Content
    )
}

extension View {
    @ViewBuilder
    public func layoutWeight(_ value: Double) -> some View
}

FlowStack

/// A view that arranges its subviews along multiple horizontal lines.
@frozen
public struct FlowStack<Content: View>: View {

    public init(
        alignment: Alignment = .center,
        spacing: CGFloat? = nil,
        @ViewBuilder content: () -> Content
    )
}

RadialStack

/// A view that arranges its subviews along a radial circumference.
@frozen
public struct RadialStack<Content: View>: View {

    public init(radius: CGFloat? = nil, @ViewBuilder content: () -> Content)
}

OptionalAdapter

/// A view maps an `Optional` value to it's `Content` or `Placeholder`.
@frozen
public struct OptionalAdapter<
    T,
    Content: View,
    Placeholder: View
>: View {

    @inlinable
    public init(
        _ value: T?,
        @ViewBuilder content: (T) -> Content,
        @ViewBuilder placeholder: () -> Placeholder
    )
}

extension OptionalAdapter where Placeholder == EmptyView {
    @inlinable
    public init(
        _ value: T?,
        @ViewBuilder content: (T) -> Content
    )
}

ResultAdapter

/// A view maps a `Result` value to it's `SuccessContent` or `FailureContent`.
@frozen
public struct ResultAdapter<
    SuccessContent: View,
    FailureContent: View
>: View {

    @inlinable
    public init<Success, Failure: Error>(
        _ value: Result<Success, Failure>,
        @ViewBuilder content: (Success) -> SuccessContent,
        @ViewBuilder placeholder: (Failure) -> FailureContent
    )
}

extension ResultAdapter where FailureContent == EmptyView {
    @inlinable
    public init<Success, Failure: Error>(
        _ value: Result<Success, Failure>,
        @ViewBuilder content: (Success) -> SuccessContent
    )
}

BindingTransform

public protocol BindingTransform {
    associatedtype Input
    associatedtype Output

    func get(_ value: Input) -> Output
    func set(_ newValue: Output, oldValue: @autoclosure () -> Input, transaction: Transaction) throws -> Input
}

extension Binding {
@inlinable
    public func projecting<Transform: BindingTransform>(
        _ transform: Transform
    ) -> Binding<Transform.Output> where Transform.Input == Value

    @inlinable
    public func isNil<Wrapped>() -> Binding<Bool> where Optional<Wrapped> == Value
    
    @inlinable
    public func isNotNil<Wrapped>() -> Binding<Bool> where Optional<Wrapped> == Value
    
    @inlinable
    public func map<T>(_ keyPath: WritableKeyPath<Value, T>) -> Binding<T>
}

SafeAreaPadding

@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
extension View {
    @inlinable
    public func safeAreaPadding(_ edgeInsets: EdgeInsets) -> some View

    @inlinable
    public func safeAreaPadding(_ length: CGFloat = 16) -> some View

    @inlinable
    public func safeAreaPadding(_ edges: Edge.Set, _ length: CGFloat = 16) -> some View
}

Badge

@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
extension View {
    @inlinable
    public func badge<Label: View>(
        alignment: Alignment = .topTrailing,
        anchor: UnitPoint = UnitPoint(x: 0.25, y: 0.25),
        scale:  CGFloat = 1.2,
        @ViewBuilder label: () -> Label
    ) -> some View
}

Accessibility

extension View {
    /// Disables accessibility elements from being generated, even when an assistive technology is running
    @inlinable
    public func accessibilityDisabled() -> some View

    /// Optionally uses the specified string to identify the view.
    @inlinable
    public func accessibilityIdentifier(_ identifier: String?) -> ModifiedContent<Self, AccessibilityAttachmentModifier>

    /// Optionally adds a label to the view that describes its contents.
    @_disfavoredOverload
    @inlinable
    public func accessibilityLabel<S: StringProtocol>(_ label: S?) -> ModifiedContent<Self, AccessibilityAttachmentModifier>

    /// Optionally adds a textual description of the value that the view contains.
    @_disfavoredOverload
    @inlinable
    public func accessibilityValue<S: StringProtocol>(_ value: S?) -> ModifiedContent<Self, AccessibilityAttachmentModifier>
    
    /// Optionally adds an accessibility action to the view.
    @inlinable
    public func accessibilityAction(named name: LocalizedStringKey?, _ handler: @escaping () -> Void) -> ModifiedContent<Self, AccessibilityAttachmentModifier>

    /// Optionally adds an accessibility action to the view.
    @_disfavoredOverload
    @inlinable
    public func accessibilityAction<S: StringProtocol>(named name: S?, _ handler: @escaping () -> Void) -> ModifiedContent<Self, AccessibilityAttachmentModifier>

And Many More

See the source files for more.

License

Distributed under the BSD 2-Clause License. See LICENSE.md for more information.

GitHub

View Github