Skip to content

Commit

Permalink
0.1.2
Browse files Browse the repository at this point in the history
  • Loading branch information
nathantannar4 committed Dec 8, 2022
1 parent 566ace8 commit a50ccdb
Show file tree
Hide file tree
Showing 19 changed files with 429 additions and 114 deletions.
67 changes: 67 additions & 0 deletions .swiftpm/xcode/xcshareddata/xcschemes/Turbocharger.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1410"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Turbocharger"
BuildableName = "Turbocharger"
BlueprintName = "Turbocharger"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Turbocharger"
BuildableName = "Turbocharger"
BlueprintName = "Turbocharger"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
103 changes: 103 additions & 0 deletions Sources/Turbocharger/Sources/Alignment/VariadicAlignmentID.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
//
// Copyright (c) Nathan Tannar
//

import SwiftUI

/// An `AlignmentID` that is resolved from multiple values
///
/// > Tip: Use ``VariadicAlignmentID`` to create alignments
/// similar to `.firstTextBaseline`
public protocol VariadicAlignmentID: AlignmentID {
static func reduce(value: inout CGFloat?, n: Int, nextValue: CGFloat)
}

private struct DefaultAlignmentID: AlignmentID {
static func defaultValue(in context: ViewDimensions) -> CGFloat { 0 }
}

extension VariadicAlignmentID {
public static func reduce(value: inout CGFloat?, n: Int, nextValue: CGFloat) {
DefaultAlignmentID._combineExplicit(childValue: nextValue, n, into: &value)
}

public static func _combineExplicit(
childValue: CGFloat,
_ n: Int,
into parentValue: inout CGFloat?
) {
reduce(value: &parentValue, n: n, nextValue: childValue)
}
}

extension View {

/// A modifier that transforms a vertical alignment to another
@inlinable
public func alignmentGuide(
_ g: VerticalAlignment,
value: VerticalAlignment
) -> some View {
alignmentGuide(g) { $0[value] }
}

/// A modifier that transforms a horizontal alignment to another
@inlinable
public func alignmentGuide(
_ g: HorizontalAlignment,
value: HorizontalAlignment
) -> some View {
alignmentGuide(g) { $0[value] }
}
}

// MARK: - Previews

struct SecondTextBaseline: VariadicAlignmentID {
static func defaultValue(in context: ViewDimensions) -> CGFloat {
context[.firstTextBaseline]
}

static func reduce(value: inout CGFloat?, n: Int, nextValue: CGFloat) {
if n == 1 {
value = nextValue
}
}
}

extension VerticalAlignment {
static let secondTextBaseline = VerticalAlignment(SecondTextBaseline.self)
}

struct VariadicAlignmentID_Previews: PreviewProvider {
static var previews: some View {
VStack(spacing: 48) {
HStack(alignment: .firstTextBaseline) {
Text("Label")

VStack(alignment: .trailing) {
Text("One")
Text("Two")
Text("Three")
}
.font(.title)
}

HStack(alignment: .secondTextBaseline) {
Text("Label")

VStack(alignment: .trailing) {
Group {
Text("One")
Text("Two")
Text("Three")
}
.alignmentGuide(.secondTextBaseline) { d in
d[VerticalAlignment.firstTextBaseline]
}
}
.font(.title)
}
}
}
}
45 changes: 0 additions & 45 deletions Sources/Turbocharger/Sources/Core/AlignmentKey.swift

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import SwiftUI
import os.log

/// A protocol for defining a transform for a `Binding`
public protocol BindingTransform {
associatedtype Input
associatedtype Output
Expand All @@ -14,6 +15,8 @@ public protocol BindingTransform {
}

extension Binding {

/// Projects a `Binding` with the `transform`
@inlinable
public func projecting<Transform: BindingTransform>(
_ transform: Transform
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

import SwiftUI

/// A ``BindingTransform`` that transforms the value
/// with a `ParseableFormatStyle`
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
public struct FormatTransform<F: ParseableFormatStyle>: BindingTransform where F.FormatInput: Equatable, F.FormatOutput == String {
public typealias Input = F.FormatInput
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

import SwiftUI

/// A ``BindingTransform`` that transforms the value to a `Bool`
///
/// The transform will return `true` when the value is `nil`. If the projected
/// value is set to `true`, the value will be set to `nil`.
@frozen
public struct IsNilTransform<Input>: BindingTransform {

Expand All @@ -23,6 +27,8 @@ public struct IsNilTransform<Input>: BindingTransform {
}

extension Binding {

/// A ``BindingTransform`` that transforms the value to `true` when `nil`
@inlinable
public func isNil<Wrapped>() -> Binding<Bool> where Optional<Wrapped> == Value {
projecting(IsNilTransform())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

import SwiftUI

/// A ``BindingTransform`` that transforms the value to a `Bool`
///
/// The transform will return `true` when the value is not `nil`. If the projected
/// value is set to `false`, the value will be set to `nil`.
@frozen
public struct IsNotNilTransform<Input>: BindingTransform {

Expand All @@ -23,6 +27,8 @@ public struct IsNotNilTransform<Input>: BindingTransform {
}

extension Binding {

/// A ``BindingTransform`` that transforms the value to `true` when not `nil`
@inlinable
public func isNotNil<Wrapped>() -> Binding<Bool> where Optional<Wrapped> == Value {
projecting(IsNotNilTransform())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import SwiftUI

/// A ``BindingTransform`` that transforms the value from a `WritableKeyPath`
@frozen
public struct MapTransform<Input, Output>: BindingTransform {

Expand All @@ -27,6 +28,8 @@ public struct MapTransform<Input, Output>: BindingTransform {
}

extension Binding {

/// A ``BindingTransform`` that transforms the value from a `WritableKeyPath`
@inlinable
public func map<T>(_ keyPath: WritableKeyPath<Value, T>) -> Binding<T> {
projecting(MapTransform(keyPath: keyPath))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// Copyright (c) Nathan Tannar
//

import SwiftUI
import Combine

/// A property wrapper that subscribes to an optional observable
/// object and invalidates a view whenever the observable object changes.
@propertyWrapper
@frozen
public struct OptionalObservedObject<ObjectType: ObservableObject>: DynamicProperty {

@usableFromInline
class Storage: ObservableObject {
weak var value: ObjectType? {
didSet {
if oldValue !== value {
value.map { bind(to: $0) }
objectWillChange.send()
}
}
}

var cancellable: AnyCancellable?

@usableFromInline
init(value: ObjectType?) {
self.value = value
value.map { bind(to: $0) }
}

func bind(to object: ObjectType) {
cancellable = object.objectWillChange
.sink { [unowned self] _ in
self.objectWillChange.send()
}
}
}

@usableFromInline
var storage: ObservedObject<Storage>

@inlinable
public init(wrappedValue: ObjectType?) {
storage = ObservedObject<Storage>(wrappedValue: Storage(value: wrappedValue))
}

public var wrappedValue: ObjectType? {
get { storage.wrappedValue.value }
nonmutating set { storage.wrappedValue.value = newValue }
}

public var projectedValue: Binding<ObjectType?> {
storage.projectedValue.value
}
}
Loading

0 comments on commit a50ccdb

Please sign in to comment.