diff --git a/Examples/Demo/Demo/Custom Transitions/Flip.swift b/Examples/Demo/Demo/Custom Transitions/Flip.swift index 26abc977..006836bf 100644 --- a/Examples/Demo/Demo/Custom Transitions/Flip.swift +++ b/Examples/Demo/Demo/Custom Transitions/Flip.swift @@ -11,10 +11,10 @@ extension AnyNavigationTransition { } } -struct Flip: NavigationTransition { +struct Flip: NavigationTransitionProtocol { var axis: Axis - var body: some NavigationTransition { + var body: some NavigationTransitionProtocol { MirrorPush { Rotate3D(.degrees(180), axis: axis == .horizontal ? (x: 1, y: 0, z: 0) : (x: 0, y: 1, z: 0)) } diff --git a/Examples/Demo/Demo/Custom Transitions/Swing.swift b/Examples/Demo/Demo/Custom Transitions/Swing.swift index c0956879..8ea0de38 100644 --- a/Examples/Demo/Demo/Custom Transitions/Swing.swift +++ b/Examples/Demo/Demo/Custom Transitions/Swing.swift @@ -7,8 +7,8 @@ extension AnyNavigationTransition { } } -struct Swing: NavigationTransition { - var body: some NavigationTransition { +struct Swing: NavigationTransitionProtocol { + var body: some NavigationTransitionProtocol { Slide(axis: .horizontal) MirrorPush { let angle = 70.0 diff --git a/Examples/Demo/Demo/Custom Transitions/Zoom.swift b/Examples/Demo/Demo/Custom Transitions/Zoom.swift index eaa539d3..dba5cfd7 100644 --- a/Examples/Demo/Demo/Custom Transitions/Zoom.swift +++ b/Examples/Demo/Demo/Custom Transitions/Zoom.swift @@ -7,8 +7,8 @@ extension AnyNavigationTransition { } } -struct Zoom: NavigationTransition { - var body: some NavigationTransition { +struct Zoom: NavigationTransitionProtocol { + var body: some NavigationTransitionProtocol { MirrorPush { Scale(0.5) OnInsertion { diff --git a/README.md b/README.md index 2f7e9c39..d067801f 100644 --- a/README.md +++ b/README.md @@ -77,8 +77,8 @@ The library ships with some **standard transitions** out of the box: In addition to these, you can create fully [**custom transitions**](https://davdroman.github.io/swiftui-navigation-transitions/main/documentation/navigationtransitions/custom-transitions/) in just a few lines of SwiftUI-like code! ```swift -struct Swing: NavigationTransition { - var body: some NavigationTransition { +struct Swing: NavigationTransitionProtocol { + var body: some NavigationTransitionProtocol { Slide(axis: .horizontal) MirrorPush { let angle = 70.0 diff --git a/Sources/NavigationTransition/AnyNavigationTransition.swift b/Sources/NavigationTransition/AnyNavigationTransition.swift index 3ce04136..b5e80a6e 100644 --- a/Sources/NavigationTransition/AnyNavigationTransition.swift +++ b/Sources/NavigationTransition/AnyNavigationTransition.swift @@ -24,7 +24,7 @@ public struct AnyNavigationTransition { package let handler: Handler package var animation: Animation? = .default - public init(_ transition: some NavigationTransition) { + public init(_ transition: some NavigationTransitionProtocol) { self.isDefault = false self.handler = .transient(transition.transition(from:to:for:in:)) } diff --git a/Sources/NavigationTransition/Combined.swift b/Sources/NavigationTransition/Combined.swift index e789b6f8..e70d2d9d 100644 --- a/Sources/NavigationTransition/Combined.swift +++ b/Sources/NavigationTransition/Combined.swift @@ -4,7 +4,7 @@ extension AnyNavigationTransition { public func combined(with other: Self) -> Self { switch (self.handler, other.handler) { case (.transient(let lhsHandler), .transient(let rhsHandler)): - struct Erased: NavigationTransition { + struct Erased: NavigationTransitionProtocol { let handler: AnyNavigationTransition.TransientHandler @inlinable @@ -30,7 +30,7 @@ extension AnyNavigationTransition { } } -public struct Combined: NavigationTransition { +public struct Combined: NavigationTransitionProtocol { private let transitionA: TransitionA private let transitionB: TransitionB diff --git a/Sources/NavigationTransition/Fade.swift b/Sources/NavigationTransition/Fade.swift index 50f18030..37960316 100644 --- a/Sources/NavigationTransition/Fade.swift +++ b/Sources/NavigationTransition/Fade.swift @@ -8,7 +8,7 @@ extension AnyNavigationTransition { } /// A transition that fades the pushed view in, fades the popped view out, or cross-fades both views. -public struct Fade: NavigationTransition { +public struct Fade: NavigationTransitionProtocol { public enum Style { case `in` case out @@ -21,7 +21,7 @@ public struct Fade: NavigationTransition { self.style = style } - public var body: some NavigationTransition { + public var body: some NavigationTransitionProtocol { switch style { case .in: MirrorPush { diff --git a/Sources/NavigationTransition/Identity.swift b/Sources/NavigationTransition/Identity.swift index f2035846..15e0d3ae 100644 --- a/Sources/NavigationTransition/Identity.swift +++ b/Sources/NavigationTransition/Identity.swift @@ -1,5 +1,5 @@ // For internal use only. -struct Identity: NavigationTransition { +struct Identity: NavigationTransitionProtocol { init() {} func transition( diff --git a/Sources/NavigationTransition/Mirror.swift b/Sources/NavigationTransition/Mirror.swift index 8ad8192a..4ad3bb73 100644 --- a/Sources/NavigationTransition/Mirror.swift +++ b/Sources/NavigationTransition/Mirror.swift @@ -1,14 +1,14 @@ import AtomicTransition /// Used to define a transition that executes on push, and executes the mirrored version of said transition on pop. -public struct MirrorPush: NavigationTransition { +public struct MirrorPush: NavigationTransitionProtocol { private let transition: Transition public init(@AtomicTransitionBuilder transition: () -> Transition) { self.transition = transition() } - public var body: some NavigationTransition { + public var body: some NavigationTransitionProtocol { OnPush { transition } @@ -22,14 +22,14 @@ extension MirrorPush: Equatable where Transition: Equatable {} extension MirrorPush: Hashable where Transition: Hashable {} /// Used to define a transition that executes on pop, and executes the mirrored version of said transition on push. -public struct MirrorPop: NavigationTransition { +public struct MirrorPop: NavigationTransitionProtocol { private let transition: Transition public init(@AtomicTransitionBuilder transition: () -> Transition) { self.transition = transition() } - public var body: some NavigationTransition { + public var body: some NavigationTransitionProtocol { OnPush { transition.mirrored() } diff --git a/Sources/NavigationTransition/NavigationTransitionBuilder.swift b/Sources/NavigationTransition/NavigationTransitionBuilder.swift index 26479f2e..42c0671e 100644 --- a/Sources/NavigationTransition/NavigationTransitionBuilder.swift +++ b/Sources/NavigationTransition/NavigationTransitionBuilder.swift @@ -1,16 +1,16 @@ @resultBuilder public enum NavigationTransitionBuilder { #if compiler(>=5.7) - public static func buildPartialBlock(first: T1) -> T1 { + public static func buildPartialBlock(first: T1) -> T1 { first } - public static func buildPartialBlock(accumulated: T1, next: T2) -> Combined { + public static func buildPartialBlock(accumulated: T1, next: T2) -> Combined { Combined(accumulated, next) } #else public static func buildBlock< - T1: NavigationTransition + T1: NavigationTransitionProtocol >( _ t1: T1 ) -> T1 { @@ -18,8 +18,8 @@ public enum NavigationTransitionBuilder { } public static func buildBlock< - T1: NavigationTransition, - T2: NavigationTransition + T1: NavigationTransitionProtocol, + T2: NavigationTransitionProtocol >( _ t1: T1, _ t2: T2 @@ -28,9 +28,9 @@ public enum NavigationTransitionBuilder { } public static func buildBlock< - T1: NavigationTransition, - T2: NavigationTransition, - T3: NavigationTransition + T1: NavigationTransitionProtocol, + T2: NavigationTransitionProtocol, + T3: NavigationTransitionProtocol >( _ t1: T1, _ t2: T2, @@ -40,10 +40,10 @@ public enum NavigationTransitionBuilder { } public static func buildBlock< - T1: NavigationTransition, - T2: NavigationTransition, - T3: NavigationTransition, - T4: NavigationTransition + T1: NavigationTransitionProtocol, + T2: NavigationTransitionProtocol, + T3: NavigationTransitionProtocol, + T4: NavigationTransitionProtocol >( _ t1: T1, _ t2: T2, @@ -54,11 +54,11 @@ public enum NavigationTransitionBuilder { } public static func buildBlock< - T1: NavigationTransition, - T2: NavigationTransition, - T3: NavigationTransition, - T4: NavigationTransition, - T5: NavigationTransition + T1: NavigationTransitionProtocol, + T2: NavigationTransitionProtocol, + T3: NavigationTransitionProtocol, + T4: NavigationTransitionProtocol, + T5: NavigationTransitionProtocol >( _ t1: T1, _ t2: T2, @@ -70,12 +70,12 @@ public enum NavigationTransitionBuilder { } public static func buildBlock< - T1: NavigationTransition, - T2: NavigationTransition, - T3: NavigationTransition, - T4: NavigationTransition, - T5: NavigationTransition, - T6: NavigationTransition + T1: NavigationTransitionProtocol, + T2: NavigationTransitionProtocol, + T3: NavigationTransitionProtocol, + T4: NavigationTransitionProtocol, + T5: NavigationTransitionProtocol, + T6: NavigationTransitionProtocol >( _ t1: T1, _ t2: T2, @@ -88,13 +88,13 @@ public enum NavigationTransitionBuilder { } public static func buildBlock< - T1: NavigationTransition, - T2: NavigationTransition, - T3: NavigationTransition, - T4: NavigationTransition, - T5: NavigationTransition, - T6: NavigationTransition, - T7: NavigationTransition + T1: NavigationTransitionProtocol, + T2: NavigationTransitionProtocol, + T3: NavigationTransitionProtocol, + T4: NavigationTransitionProtocol, + T5: NavigationTransitionProtocol, + T6: NavigationTransitionProtocol, + T7: NavigationTransitionProtocol >( _ t1: T1, _ t2: T2, @@ -108,7 +108,7 @@ public enum NavigationTransitionBuilder { } #endif - public static func buildOptional(_ component: T?) -> _OptionalTransition { + public static func buildOptional(_ component: T?) -> _OptionalTransition { if let component { return _OptionalTransition(component) } else { @@ -116,16 +116,16 @@ public enum NavigationTransitionBuilder { } } - public static func buildEither(first component: TrueTransition) -> _ConditionalTransition { + public static func buildEither(first component: TrueTransition) -> _ConditionalTransition { _ConditionalTransition(trueTransition: component) } - public static func buildEither(second component: FalseTransition) -> _ConditionalTransition { + public static func buildEither(second component: FalseTransition) -> _ConditionalTransition { _ConditionalTransition(falseTransition: component) } } -public struct _OptionalTransition: NavigationTransition { +public struct _OptionalTransition: NavigationTransitionProtocol { private let transition: Transition? init(_ transition: Transition?) { @@ -142,7 +142,7 @@ public struct _OptionalTransition: NavigationT } } -public struct _ConditionalTransition: NavigationTransition { +public struct _ConditionalTransition: NavigationTransitionProtocol { private typealias Transition = _Either private let transition: Transition diff --git a/Sources/NavigationTransition/NavigationTransition.swift b/Sources/NavigationTransition/NavigationTransitionProtocol.swift similarity index 94% rename from Sources/NavigationTransition/NavigationTransition.swift rename to Sources/NavigationTransition/NavigationTransitionProtocol.swift index 220f2531..ae5b0f7b 100644 --- a/Sources/NavigationTransition/NavigationTransition.swift +++ b/Sources/NavigationTransition/NavigationTransitionProtocol.swift @@ -7,7 +7,7 @@ import UIKit /// /// Although the library ships with a set of predefined transitions (e.g. ``Slide``, one can also create /// entirely new, fully customizable transitions by conforming to this protocol. -public protocol NavigationTransition { +public protocol NavigationTransitionProtocol { /// Typealias for `AnimatorTransientView`. typealias TransientView = AnimatorTransientView /// Typealias for `NavigationTransitionOperation`. @@ -54,7 +54,7 @@ public protocol NavigationTransition { var body: Body { get } } -extension NavigationTransition where Body: NavigationTransition { +extension NavigationTransitionProtocol where Body: NavigationTransitionProtocol { /// Invokes ``body``'s implementation of ``transition(from:to:for:in:)-211yh``. @inlinable public func transition( @@ -67,7 +67,7 @@ extension NavigationTransition where Body: NavigationTransition { } } -extension NavigationTransition where Body == Never { +extension NavigationTransitionProtocol where Body == Never { /// A non-existent body. /// /// > Warning: Do not invoke this property directly. It will trigger a fatal error at runtime. diff --git a/Sources/NavigationTransition/On.swift b/Sources/NavigationTransition/On.swift index a6b56a62..1fdae195 100644 --- a/Sources/NavigationTransition/On.swift +++ b/Sources/NavigationTransition/On.swift @@ -1,7 +1,7 @@ import AtomicTransition /// Used to define a transition that executes only on push. -public struct OnPush: NavigationTransition { +public struct OnPush: NavigationTransitionProtocol { private let transition: Transition public init(@AtomicTransitionBuilder transition: () -> Transition) { @@ -28,7 +28,7 @@ extension OnPush: Equatable where Transition: Equatable {} extension OnPush: Hashable where Transition: Hashable {} /// Used to define a transition that executes only on pop. -public struct OnPop: NavigationTransition { +public struct OnPop: NavigationTransitionProtocol { private let transition: Transition public init(@AtomicTransitionBuilder transition: () -> Transition) { diff --git a/Sources/NavigationTransition/Pick.swift b/Sources/NavigationTransition/Pick.swift index 686376d2..481e262f 100644 --- a/Sources/NavigationTransition/Pick.swift +++ b/Sources/NavigationTransition/Pick.swift @@ -1,5 +1,5 @@ -/// Used to isolate the push portion of a full `NavigationTransition` and execute it on push, ignoring the pop portion. -public struct PickPush: NavigationTransition { +/// Used to isolate the push portion of a full `NavigationTransitionProtocol` and execute it on push, ignoring the pop portion. +public struct PickPush: NavigationTransitionProtocol { private let transition: Transition public init(@NavigationTransitionBuilder transition: () -> Transition) { @@ -24,8 +24,8 @@ public struct PickPush: NavigationTransition { extension PickPush: Equatable where Transition: Equatable {} extension PickPush: Hashable where Transition: Hashable {} -/// Used to isolate the pop portion of a full `NavigationTransition` and execute it on pop, ignoring the push portion. -public struct PickPop: NavigationTransition { +/// Used to isolate the pop portion of a full `NavigationTransitionProtocol` and execute it on pop, ignoring the push portion. +public struct PickPop: NavigationTransitionProtocol { private let transition: Transition public init(@NavigationTransitionBuilder transition: () -> Transition) { diff --git a/Sources/NavigationTransition/PrimitiveNavigationTransition.swift b/Sources/NavigationTransition/PrimitiveNavigationTransition.swift index 37f3a83a..8ea39835 100644 --- a/Sources/NavigationTransition/PrimitiveNavigationTransition.swift +++ b/Sources/NavigationTransition/PrimitiveNavigationTransition.swift @@ -6,7 +6,7 @@ import UIKit /// This protocol variant is used to implement transitions that need to interact with raw UIKit transitioning entities. /// /// - Warning: Usage of this initializer is highly discouraged unless you know what you're doing. -/// Conform to ``NavigationTransition`` instead to ensure correct transition behavior. +/// Conform to ``NavigationTransitionProtocol`` instead to ensure correct transition behavior. public protocol PrimitiveNavigationTransition { /// Typealias for `NavigationTransitionOperation`. typealias TransitionOperation = NavigationTransitionOperation diff --git a/Sources/NavigationTransition/Slide.swift b/Sources/NavigationTransition/Slide.swift index e1104da7..2d14b030 100644 --- a/Sources/NavigationTransition/Slide.swift +++ b/Sources/NavigationTransition/Slide.swift @@ -25,7 +25,7 @@ extension AnyNavigationTransition { /// This transition: /// - Pushes views right-to-left and pops views left-to-right when `axis` is `horizontal`. /// - Pushes views bottom-to-top and pops views top-to-bottom when `axis` is `vertical`. -public struct Slide: NavigationTransition { +public struct Slide: NavigationTransitionProtocol { private let axis: Axis public init(axis: Axis) { @@ -38,7 +38,7 @@ public struct Slide: NavigationTransition { self.init(axis: .horizontal) } - public var body: some NavigationTransition { + public var body: some NavigationTransitionProtocol { switch axis { case .horizontal: MirrorPush { diff --git a/Sources/NavigationTransitions/Documentation.docc/Articles/Custom Transitions.md b/Sources/NavigationTransitions/Documentation.docc/Articles/Custom Transitions.md index 19c5bf51..109a2f08 100644 --- a/Sources/NavigationTransitions/Documentation.docc/Articles/Custom Transitions.md +++ b/Sources/NavigationTransitions/Documentation.docc/Articles/Custom Transitions.md @@ -15,7 +15,7 @@ As a first time reader, it is highly recommended that you read **Core Concepts** ## Core Concepts -### `NavigationTransition` +### `NavigationTransitionProtocol` The main construct the library leverages is called `AnyNavigationTransition`. You may have seen some instances of this type in the README's code samples (e.g. `.slide`). @@ -32,19 +32,19 @@ extension AnyNavigationTransition { } ``` -As you can see, there's not much going on here. The reason is that `AnyNavigationTransition` is actually just a type erasing wrapper around the real meat and potatoes: the protocol `NavigationTransition`. +As you can see, there's not much going on here. The reason is that `AnyNavigationTransition` is actually just a type erasing wrapper around the real meat and potatoes: the protocol `NavigationTransitionProtocol`. Let's take a look at what (capital "S") `Slide` is: ```swift -public struct Slide: NavigationTransition { +public struct Slide: NavigationTransitionProtocol { private let axis: Axis public init(axis: Axis) { self.axis = axis } - public var body: some NavigationTransition { + public var body: some NavigationTransitionProtocol { switch axis { case .horizontal: MirrorPush { @@ -71,7 +71,7 @@ public struct Slide: NavigationTransition { This is more like it! -As you can see, `NavigationTransition` leverages result builder syntax to define "what" transitions do, not "how" they do it. Notice how the entire transition is implemented concisely, yet there's **no explicit `UIView` animation** code to be seen anywhere at this point. I'd like to direct your attention instead to what's actually describing the transition at its core: `Move(edge: ...)`. +As you can see, `NavigationTransitionProtocol` leverages result builder syntax to define "what" transitions do, not "how" they do it. Notice how the entire transition is implemented concisely, yet there's **no explicit `UIView` animation** code to be seen anywhere at this point. I'd like to direct your attention instead to what's actually describing the transition at its core: `Move(edge: ...)`. If you've used SwiftUI's `transition` modifier before, it's easy to draw a comparison to `AnyTransition.move(edge:)`. And in fact, whilst the API is slightly different, the intent behind it is the same indeed! `Move` is a type that conforms to the building block of the library: `AtomicTransition`. @@ -79,7 +79,7 @@ If you've used SwiftUI's `transition` modifier before, it's easy to draw a compa `AtomicTransition` is a SwiftUI `AnyTransition`-inspired type which acts very much in the same manner. It can describe a specific set of view changes on an individual ("atomic") basis, for both **insertion** and **removal** of said view. -Contrary to `NavigationTransition` and as the name indicates, `AtomicTransition` applies to only a **single view** out of the two, and is **agnostic** as to the **intent** (push or pop) of its **parent** `NavigationTransition`. +Contrary to `NavigationTransitionProtocol` and as the name indicates, `AtomicTransition` applies to only a **single view** out of the two, and is **agnostic** as to the **intent** (push or pop) of its **parent** `NavigationTransitionProtocol`. If we dive even deeper into `Move`, this is what we find: @@ -147,7 +147,7 @@ You can create a custom `AnyNavigationTransition` by combining two existing tran It is rarely the case where you'd want to combine `AnyNavigationTransition`s in this manner due to their nature as high level abstractions. In fact, most of the time they won't combine very well at all, and will produce glitchy or weird effects. This is because two or more fully-fledged transitions tend to override the same view properties with different values, producing unexpected outcomes. -Instead, most combinations should happen at lowers level, in `NavigationTransition` and `AtomicTransition` conformances. +Instead, most combinations should happen at lowers level, in `NavigationTransitionProtocol` and `AtomicTransition` conformances. Regardless, it's still allowed for cases like `slide` + `fade(in:)`, which affect completely different properties of the view. Separatedly, `slide` only moves the views horizontally, and `.fade(.in)` fades views in. When combined, both occur at the same time without interfering with each other. @@ -209,17 +209,17 @@ All types conforming to `AtomicTransition` must implement what's known as a "tra --- -Next up, let's explore two ways of conforming to `NavigationTransition`. +Next up, let's explore two ways of conforming to `NavigationTransitionProtocol`. -The simplest (and most recommended) way is by declaring our atomic transitions (if needed), and composing them via `var body: some NavigationTransition { ... }` like we saw [previously with `Slide`](#NavigationTransition). +The simplest (and most recommended) way is by declaring our atomic transitions (if needed), and composing them via `var body: some NavigationTransitionProtocol { ... }` like we saw [previously with `Slide`](#NavigationTransitionProtocol). -Check out the [documentation](https://swiftpackageindex.com/davdroman/swiftui-navigation-transitions/0.2.0/documentation/navigationtransitions/navigationtransition) to learn about the different `NavigationTransition` types and how they compose. +Check out the [documentation](https://swiftpackageindex.com/davdroman/swiftui-navigation-transitions/0.2.0/documentation/navigationtransitions/NavigationTransitionProtocol) to learn about the different `NavigationTransitionProtocol` types and how they compose. The Demo project in the repo is also a great source of learning about different types of custom transitions and the way to implement them. --- -Finally, let's explore an alternative option for those who'd like to reach for a more wholistic API. `NavigationTransition` declares a `transition` function that can be implemented instead of `body`: +Finally, let's explore an alternative option for those who'd like to reach for a more wholistic API. `NavigationTransitionProtocol` declares a `transition` function that can be implemented instead of `body`: ```swift func transition(from fromView: TransientView, to toView: TransientView, for operation: TransitionOperation, in container: Container)