diff --git a/ComposableArchitecture.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ComposableArchitecture.xcworkspace/xcshareddata/swiftpm/Package.resolved index 94998dfcc7d3..89ba4b1bca4b 100644 --- a/ComposableArchitecture.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ComposableArchitecture.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "7bde44da63d64357331b7d73c1c3f9d1aa732b1793a1d1fc5879f2c192bef69c", + "originHash" : "3ebb70e4ef5203d6f8bebecc1bec69837803b880f6f397952a6f49aa1f6fe107", "pins" : [ { "identity" : "combine-schedulers", @@ -105,8 +105,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-navigation", "state" : { - "revision" : "e28911721538fa0c2439e92320bad13e3200866f", - "version" : "2.2.3" + "revision" : "db6bc9dbfed001f21e6728fd36413d9342c235b4", + "version" : "2.3.0" } }, { diff --git a/Package.swift b/Package.swift index 387d16f78460..043e869e5b00 100644 --- a/Package.swift +++ b/Package.swift @@ -26,7 +26,7 @@ let package = Package( .package(url: "https://github.com/pointfreeco/swift-dependencies", from: "1.4.0"), .package(url: "https://github.com/pointfreeco/swift-identified-collections", from: "1.1.0"), .package(url: "https://github.com/pointfreeco/swift-macro-testing", from: "0.2.0"), - .package(url: "https://github.com/pointfreeco/swift-navigation", from: "2.2.2"), + .package(url: "https://github.com/pointfreeco/swift-navigation", from: "2.3.0"), .package(url: "https://github.com/pointfreeco/swift-perception", from: "1.3.4"), .package(url: "https://github.com/pointfreeco/swift-sharing", "0.1.2"..<"3.0.0"), .package(url: "https://github.com/pointfreeco/xctest-dynamic-overlay", from: "1.3.0"), diff --git a/Package@swift-6.0.swift b/Package@swift-6.0.swift index 15705d2b5210..ef27ccbf0b81 100644 --- a/Package@swift-6.0.swift +++ b/Package@swift-6.0.swift @@ -26,7 +26,7 @@ let package = Package( .package(url: "https://github.com/pointfreeco/swift-dependencies", from: "1.4.0"), .package(url: "https://github.com/pointfreeco/swift-identified-collections", from: "1.1.0"), .package(url: "https://github.com/pointfreeco/swift-macro-testing", from: "0.2.0"), - .package(url: "https://github.com/pointfreeco/swift-navigation", from: "2.2.2"), + .package(url: "https://github.com/pointfreeco/swift-navigation", from: "2.3.0"), .package(url: "https://github.com/pointfreeco/swift-perception", from: "1.3.4"), .package(url: "https://github.com/pointfreeco/swift-sharing", "0.1.2"..<"3.0.0"), .package(url: "https://github.com/pointfreeco/xctest-dynamic-overlay", from: "1.3.0"), diff --git a/Sources/ComposableArchitecture/Documentation.docc/Extensions/UIKit.md b/Sources/ComposableArchitecture/Documentation.docc/Extensions/UIKit.md index e73bfa637504..90f76f54da9a 100644 --- a/Sources/ComposableArchitecture/Documentation.docc/Extensions/UIKit.md +++ b/Sources/ComposableArchitecture/Documentation.docc/Extensions/UIKit.md @@ -16,7 +16,12 @@ integrate into application code written in UIKit. ### Presenting alerts and action sheets -- ``UIKit/UIAlertController/init(store:)`` +- ``UIKit/UIAlertController`` + +### Stack-based navigation + +- ``UIKitNavigation/NavigationStackController`` +- ``UIKitNavigation/UIPushAction`` ### Combine integration diff --git a/Sources/ComposableArchitecture/TestStore.swift b/Sources/ComposableArchitecture/TestStore.swift index c2a0a2cd6a1f..10f74dd49e65 100644 --- a/Sources/ComposableArchitecture/TestStore.swift +++ b/Sources/ComposableArchitecture/TestStore.swift @@ -729,30 +729,24 @@ public final class TestStore { line: UInt, column: UInt ) { - // NB: This existential opening can go away if we can constrain 'State: Equatable' at the - // 'TestStore' level, but for some reason this breaks DocC. - if self.sharedChangeTracker.hasChanges, let stateType = State.self as? any Equatable.Type { - func open(_: EquatableState.Type) { - let store = self as! TestStore - try? store.expectedStateShouldMatch( - preamble: "Test store finished before asserting against changes to shared state", - postamble: """ + if sharedChangeTracker.hasChanges { + try? expectedStateShouldMatch( + preamble: "Test store finished before asserting against changes to shared state", + postamble: """ Invoke "TestStore.assert" at the end of this test to assert against changes to shared \ state. """, - expected: store.state, - actual: store.state, - updateStateToExpectedResult: nil, - skipUnnecessaryModifyFailure: true, - fileID: fileID, - filePath: filePath, - line: line, - column: column - ) - } - open(stateType) - self.sharedChangeTracker.reset() + expected: state, + actual: state, + updateStateToExpectedResult: nil, + skipUnnecessaryModifyFailure: true, + fileID: fileID, + filePath: filePath, + line: line, + column: column + ) } + sharedChangeTracker.reset() } /// Overrides the store's dependencies for a given operation. diff --git a/Sources/ComposableArchitecture/UIKit/NavigationStackControllerUIKit.swift b/Sources/ComposableArchitecture/UIKit/NavigationStackControllerUIKit.swift index da5c584cead1..bf4c29703ce1 100644 --- a/Sources/ComposableArchitecture/UIKit/NavigationStackControllerUIKit.swift +++ b/Sources/ComposableArchitecture/UIKit/NavigationStackControllerUIKit.swift @@ -2,7 +2,6 @@ import UIKit extension NavigationStackController { - /// Drives a navigation stack controller with a store. /// /// See the dedicated article on for more information on the library's @@ -69,4 +68,36 @@ } } } + + @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) + @MainActor + extension UIPushAction { + /// Pushes an element of ``StackState`` onto the current navigation stack. + /// + /// This is the UIKit equivalent of + /// ``SwiftUI/NavigationLink/init(state:label:fileID:filePath:line:column:)``. + /// + /// - Parameters: + /// - state: An element of stack state. + /// - fileID: The source `#fileID` associated with the push. + /// - filePath: The source `#filePath` associated with the push. + /// - line: The source `#line` associated with the push. + /// - column: The source `#column` associated with the push. + public func callAsFunction( + state: Element, + fileID: StaticString = #fileID, + filePath: StaticString = #filePath, + line: UInt = #line, + column: UInt = #column + ) { + @Dependency(\.stackElementID) var stackElementID + self( + value: StackState.Component(id: stackElementID(), element: state), + fileID: fileID, + filePath: filePath, + line: line, + column: column + ) + } + } #endif