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.