From 7ab04c6e2e6a73d34d5a762970ef88bf0aedb084 Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Tue, 28 May 2024 10:16:33 -0700 Subject: [PATCH] Fix DocC and update `NavigationLink(unwrapping:)` (#158) * Fix DocC and update `NavigationLink(unwrapping:)` * wip * wip --- .../Documentation.docc/Articles/Navigation.md | 12 +++++----- .../Articles/WhatIsNavigation.md | 2 +- .../Extensions/Deprecations.md | 1 + .../SwiftUINavigation/FullScreenCover.swift | 8 +++---- .../Internal/Deprecations.swift | 22 ++++++++++++++++- .../NavigationDestination.swift | 2 +- .../SwiftUINavigation/NavigationLink.swift | 24 +++++++++---------- Sources/SwiftUINavigation/Popover.swift | 10 ++++---- Sources/SwiftUINavigation/Sheet.swift | 7 +++--- .../ConfirmationDialogState.swift | 4 ++-- 10 files changed, 57 insertions(+), 35 deletions(-) diff --git a/Sources/SwiftUINavigation/Documentation.docc/Articles/Navigation.md b/Sources/SwiftUINavigation/Documentation.docc/Articles/Navigation.md index 2320d5bdd8..93310cd8c8 100644 --- a/Sources/SwiftUINavigation/Documentation.docc/Articles/Navigation.md +++ b/Sources/SwiftUINavigation/Documentation.docc/Articles/Navigation.md @@ -25,7 +25,7 @@ non-`nil`. You can construct a `NavigationLink` that will activate when that sta non-`nil`, and will deactivate when the state becomes `nil`: ```swift -NavigationLink(unwrapping: $destination) { isActive in +NavigationLink(item: $destination) { isActive in destination = isActive ? 42 : nil } destination: { $number in CounterView(number: $number) @@ -81,12 +81,12 @@ one of these destinations: ``` With this set up you can make use of the -``SwiftUI/NavigationLink/init(unwrapping:onNavigate:destination:label:)`` initializer on +``SwiftUI/NavigationLink/init(item:onNavigate:destination:label:)`` initializer on `NavigationLink` in order to specify a binding to the optional destination, and further specify which case of the enum you want driving navigation: ```swift -NavigationLink(unwrapping: $destination.counter) { isActive in +NavigationLink(item: $destination.counter) { isActive in destination = isActive ? .counter(42) : nil } destination: { $number in CounterView(number: $number) @@ -95,7 +95,7 @@ NavigationLink(unwrapping: $destination.counter) { isActive in } ``` -And similarly for ``SwiftUI/View/navigationDestination(unwrapping:destination:)``: +And similarly for ``SwiftUI/View/navigationDestination(item:destination:)``: ```swift Button { @@ -103,7 +103,7 @@ Button { } label: { Text("Go to counter") } -.navigationDestination(unwrapping: $model.destination.counter) { $number in +.navigationDestination(item: $model.destination.counter) { $number in CounterView(number: $number) } ``` @@ -113,7 +113,7 @@ Button { ### Navigation views and modifiers - ``SwiftUI/View/navigationDestination(item:destination:)`` -- ``SwiftUI/NavigationLink/init(unwrapping:onNavigate:destination:label:)`` +- ``SwiftUI/NavigationLink/init(item:onNavigate:destination:label:)`` ### Supporting types diff --git a/Sources/SwiftUINavigation/Documentation.docc/Articles/WhatIsNavigation.md b/Sources/SwiftUINavigation/Documentation.docc/Articles/WhatIsNavigation.md index 188202a5b5..2ef7ab4853 100644 --- a/Sources/SwiftUINavigation/Documentation.docc/Articles/WhatIsNavigation.md +++ b/Sources/SwiftUINavigation/Documentation.docc/Articles/WhatIsNavigation.md @@ -266,7 +266,7 @@ later. If you must support iOS 15 and earlier, you can use the following initial `NavigationLink`, which also has a very similar API to the above: ```swift -NavigationLink(unwrapping: $model.destination.edit) { isActive in +NavigationLink(item: $model.destination.edit) { isActive in model.setEditIsActive(isActive) } destination: { $item in EditItemView(item: $item) diff --git a/Sources/SwiftUINavigation/Documentation.docc/Extensions/Deprecations.md b/Sources/SwiftUINavigation/Documentation.docc/Extensions/Deprecations.md index c9c45d6276..d220b913af 100644 --- a/Sources/SwiftUINavigation/Documentation.docc/Extensions/Deprecations.md +++ b/Sources/SwiftUINavigation/Documentation.docc/Extensions/Deprecations.md @@ -13,6 +13,7 @@ instead. - ``IfLet`` - ``IfCaseLet`` +- ``SwiftUI/NavigationLink/init(unwrapping:onNavigate:destination:label:)`` - ``SwiftUI/NavigationLink/init(unwrapping:case:onNavigate:destination:label:)`` - ``SwiftUI/NavigationLink/init(unwrapping:destination:onNavigate:label:)`` - ``SwiftUI/NavigationLink/init(unwrapping:case:destination:onNavigate:label:)`` diff --git a/Sources/SwiftUINavigation/FullScreenCover.swift b/Sources/SwiftUINavigation/FullScreenCover.swift index 92daf52e29..75cb77af23 100644 --- a/Sources/SwiftUINavigation/FullScreenCover.swift +++ b/Sources/SwiftUINavigation/FullScreenCover.swift @@ -60,8 +60,8 @@ /// Presents a full-screen cover using a binding as a data source for the sheet's content. /// - /// A version of ``fullScreenCover(item:id:onDismiss:content:)-14to1`` that takes an - /// identifiable item. + /// A version of ``SwiftUI/View/fullScreenCover(item:id:onDismiss:content:)-14to1`` that takes + /// an identifiable item. /// /// - Parameters: /// - item: A binding to an optional source of truth for the sheet. When `item` is non-`nil`, @@ -82,8 +82,8 @@ /// Presents a full-screen cover using a binding as a data source for the sheet's content. /// - /// A version of ``fullScreenCover(item:id:onDismiss:content:)-14to1`` that is passed an item - /// and not a binding to an item. + /// A version of ``SwiftUI/View/fullScreenCover(item:id:onDismiss:content:)-14to1`` that is + /// passed an item and not a binding to an item. /// /// - Parameters: /// - item: A binding to an optional source of truth for the sheet. When `item` is non-`nil`, diff --git a/Sources/SwiftUINavigation/Internal/Deprecations.swift b/Sources/SwiftUINavigation/Internal/Deprecations.swift index 76751085ed..4afc9722fe 100644 --- a/Sources/SwiftUINavigation/Internal/Deprecations.swift +++ b/Sources/SwiftUINavigation/Internal/Deprecations.swift @@ -118,6 +118,26 @@ } } + @available(iOS, introduced: 13, deprecated: 16) + @available(macOS, introduced: 10.15, deprecated: 13) + @available(tvOS, introduced: 13, deprecated: 16) + @available(watchOS, introduced: 6, deprecated: 9) + extension NavigationLink { + @available(*, deprecated, renamed: "init(item:onNavigate:destination:label:)") + public init( + unwrapping value: Binding, + onNavigate: @escaping (_ isActive: Bool) -> Void, + @ViewBuilder destination: @escaping (Binding) -> WrappedDestination, + @ViewBuilder label: () -> Label + ) where Destination == WrappedDestination? { + self.init( + destination: Binding(unwrapping: value).map(destination), + isActive: value.isPresent().didSet(onNavigate), + label: label + ) + } + } + // NB: Deprecated after 1.2.1 @available(iOS 15, macOS 12, tvOS 15, watchOS 8, *) @@ -681,7 +701,7 @@ @ViewBuilder label: () -> Label ) where Destination == WrappedDestination? { self.init( - unwrapping: `enum`.case(casePath), + item: `enum`.case(casePath), onNavigate: onNavigate, destination: destination, label: label diff --git a/Sources/SwiftUINavigation/NavigationDestination.swift b/Sources/SwiftUINavigation/NavigationDestination.swift index fdf72340c2..fbd3ba95b8 100644 --- a/Sources/SwiftUINavigation/NavigationDestination.swift +++ b/Sources/SwiftUINavigation/NavigationDestination.swift @@ -17,7 +17,7 @@ /// Button("Compose") { /// self.draft = Post() /// } - /// .navigationDestination(unwrapping: $draft) { $draft in + /// .navigationDestination(item: $draft) { $draft in /// ComposeView(post: $draft, onSubmit: { ... }) /// } /// } diff --git a/Sources/SwiftUINavigation/NavigationLink.swift b/Sources/SwiftUINavigation/NavigationLink.swift index b604a7919e..0dd89b713c 100644 --- a/Sources/SwiftUINavigation/NavigationLink.swift +++ b/Sources/SwiftUINavigation/NavigationLink.swift @@ -7,7 +7,7 @@ /// /// > Note: This interface is deprecated to match the availability of the corresponding SwiftUI /// > API. If you are targeting iOS 16 or later, use - /// > ``SwiftUI/View/navigationDestination(unwrapping:destination:)``, instead. + /// > ``SwiftUI/View/navigationDestination(item:destination:)``, instead. /// /// This allows you to drive navigation to a destination from an optional value. When the /// optional value becomes non-`nil` a binding to an honest value is derived and passed to the @@ -21,8 +21,8 @@ /// /// var body: some View { /// ForEach(self.posts) { post in - /// NavigationLink(unwrapping: self.$postToEdit) { isActive in - /// self.postToEdit = isActive ? post : nil + /// NavigationLink(item: $postToEdit) { isActive in + /// postToEdit = isActive ? post : nil /// } destination: { $draft in /// EditPostView(post: $draft) /// } label: { @@ -39,30 +39,30 @@ /// ``` /// /// - Parameters: - /// - value: A binding to an optional source of truth for the destination. When `value` is + /// - item: A binding to an optional source of truth for the destination. When `item` is /// non-`nil`, a non-optional binding to the value is passed to the `destination` closure. /// The destination can use this binding to produce its content and write changes back to - /// the source of truth. Upstream changes to `value` will also be instantly reflected in the - /// destination. If `value` becomes `nil`, the destination is dismissed. + /// the source of truth. Upstream changes to `item` will also be instantly reflected in the + /// destination. If `item` becomes `nil`, the destination is dismissed. /// - onNavigate: A closure that executes when the link becomes active or inactive with a /// boolean that describes if the link was activated or not. Use this closure to populate /// the source of truth when it is passed a value of `true`. When passed `false`, the system - /// will automatically write `nil` to `value`. + /// will automatically write `nil` to `item`. /// - destination: A view for the navigation link to present. /// - label: A view builder to produce a label describing the `destination` to present. @available(iOS, introduced: 13, deprecated: 16) @available(macOS, introduced: 10.15, deprecated: 13) @available(tvOS, introduced: 13, deprecated: 16) @available(watchOS, introduced: 6, deprecated: 9) - public init( - unwrapping value: Binding, + public init( + item: Binding, onNavigate: @escaping (_ isActive: Bool) -> Void, - @ViewBuilder destination: @escaping (Binding) -> WrappedDestination, + @ViewBuilder destination: @escaping (Binding) -> WrappedDestination, @ViewBuilder label: () -> Label ) where Destination == WrappedDestination? { self.init( - destination: Binding(unwrapping: value).map(destination), - isActive: value.isPresent().didSet(onNavigate), + destination: Binding(unwrapping: item).map(destination), + isActive: item.isPresent().didSet(onNavigate), label: label ) } diff --git a/Sources/SwiftUINavigation/Popover.swift b/Sources/SwiftUINavigation/Popover.swift index 574acd2f3a..ee17ae2327 100644 --- a/Sources/SwiftUINavigation/Popover.swift +++ b/Sources/SwiftUINavigation/Popover.swift @@ -24,7 +24,7 @@ /// Button("Compose") { /// self.draft = Post() /// } - /// .popover(unwrapping: $draft) { $draft in + /// .popover(item: $draft) { $draft in /// ComposeView(post: $draft, onSubmit: { ... }) /// } /// } @@ -70,8 +70,8 @@ /// Presents a full-screen cover using a binding as a data source for the sheet's content. /// - /// A version of ``fullScreenCover(item:id:onDismiss:content:)-14to1`` that takes an - /// identifiable item. + /// A version of ``SwiftUI/View/fullScreenCover(item:id:onDismiss:content:)-14to1`` that takes + /// an identifiable item. /// /// - Parameters: /// - item: A binding to an optional source of truth for the popover. When `item` is @@ -106,8 +106,8 @@ /// Presents a popover using a binding as a data source for the sheet's content based on the /// identity of the underlying item. /// - /// A version of ``popover(item:id:attachmentAnchor:arrowEdge:content:)-3un96`` that is passed - /// an item and not a binding to an item. + /// A version of ``SwiftUI/View/popover(item:id:attachmentAnchor:arrowEdge:content:)-3un96`` + /// that is passed an item and not a binding to an item. /// /// - Parameters: /// - item: A binding to an optional source of truth for the popover. When `item` is diff --git a/Sources/SwiftUINavigation/Sheet.swift b/Sources/SwiftUINavigation/Sheet.swift index 22d9f86104..21ea1621d3 100644 --- a/Sources/SwiftUINavigation/Sheet.swift +++ b/Sources/SwiftUINavigation/Sheet.swift @@ -64,7 +64,8 @@ /// Presents a sheet using a binding as a data source for the sheet's content. /// - /// A version of ``sheet(item:id:onDismiss:content:)-1hi9l`` that takes an identifiable item. + /// A version of ``SwiftUI/View/sheet(item:id:onDismiss:content:)-1hi9l`` that takes an + /// identifiable item. /// /// - Parameters: /// - item: A binding to an optional source of truth for the sheet. When `item` is non-`nil`, @@ -85,8 +86,8 @@ /// Presents a sheet using a binding as a data source for the sheet's content. /// - /// A version of ``sheet(item:id:onDismiss:content:)-1hi9l`` that is passed an item and not a - /// binding to an item. + /// A version of ``SwiftUI/View/sheet(item:id:onDismiss:content:)-1hi9l`` that is passed an item + /// and not a binding to an item. /// /// - Parameters: /// - item: A binding to an optional source of truth for the sheet. When `item` is non-`nil`, diff --git a/Sources/SwiftUINavigationCore/ConfirmationDialogState.swift b/Sources/SwiftUINavigationCore/ConfirmationDialogState.swift index ef9f86a10d..0fa20e7e7b 100644 --- a/Sources/SwiftUINavigationCore/ConfirmationDialogState.swift +++ b/Sources/SwiftUINavigationCore/ConfirmationDialogState.swift @@ -70,7 +70,7 @@ /// } /// ``` /// - /// And in your view you can use the `.confirmationDialog(unwrapping:action:)` view modifier to + /// And in your view you can use the `.confirmationDialog(_:action:)` view modifier to /// present the dialog: /// /// ```swift @@ -83,7 +83,7 @@ /// self.model.infoButtonTapped() /// } /// } - /// .confirmationDialog(unwrapping: self.$model.dialog) { action in + /// .confirmationDialog($model.dialog) { action in /// self.model.dialogButtonTapped(action) /// } /// }