From 5e135f1ccab6f7966ff455d938aa07aa77086b04 Mon Sep 17 00:00:00 2001 From: janpollak <40995260+janpollak@users.noreply.github.com> Date: Wed, 20 May 2026 10:30:50 +0200 Subject: [PATCH 1/2] Rename TabCoordinator.Tab associatedtype to TabValue Avoids name collision with SwiftUI.Tab inside conformer scope so TabContentFlow content builders can use bare `Tab(...)` instead of `SwiftUI.Tab(...)`. Also updates the Tab Coordinator template to use TabContentFlow with the iOS 18+ Tab API and cleans the resolved part of the experiment TODO on TabCoordinator. --- .../Architecture/Coordinator.swift | 11 ++++---- .../Architecture/TabViewFlow.swift | 10 +++---- ...ordinatorIdentifier___TabCoordinator.swift | 26 ++++++++----------- 3 files changed, 21 insertions(+), 26 deletions(-) diff --git a/Sources/FuturedArchitecture/Architecture/Coordinator.swift b/Sources/FuturedArchitecture/Architecture/Coordinator.swift index dbfda47..4d4ca78 100644 --- a/Sources/FuturedArchitecture/Architecture/Coordinator.swift +++ b/Sources/FuturedArchitecture/Architecture/Coordinator.swift @@ -66,15 +66,14 @@ extension Coordinator { } /// `TabCoordinator` provides additional requirements for the use with ``SwiftUI.TabView``. -/// This *coordinator* is ment to have ``TabViewFlow`` as the Root view. +/// This *coordinator* is ment to have ``TabViewFlow`` (or ``TabContentFlow`` on iOS 18+) as the Root view. /// - Experiment: This API is in preview and subject to change. -/// - Todo: ``SwiftUI.TabView`` requires internal state, which is forbidden as per -/// documentation of ``Coordinator.rootView(with:)``. Also, the API introduces `Tab` type -/// which is essentially duplication of `Destination`. Consider, how the API limits the use of tabs. public protocol TabCoordinator: Coordinator { - associatedtype Tab: Hashable + /// The `Hashable` value used to identify the currently selected tab. Matches the `value:` + /// parameter of ``SwiftUI.Tab`` when using ``TabContentFlow``. + associatedtype TabValue: Hashable - var selectedTab: Tab { get set } + var selectedTab: TabValue { get set } } /// `NavigationStackCoordinator` provides additional requirements for use with ``SwiftUI.NavigationStack``. diff --git a/Sources/FuturedArchitecture/Architecture/TabViewFlow.swift b/Sources/FuturedArchitecture/Architecture/TabViewFlow.swift index 92c9b63..6a1c7e0 100644 --- a/Sources/FuturedArchitecture/Architecture/TabViewFlow.swift +++ b/Sources/FuturedArchitecture/Architecture/TabViewFlow.swift @@ -42,20 +42,20 @@ public struct TabViewFlow: View { /// Usage: /// ```swift /// TabContentFlow(coordinator: instance) { -/// Tab("Home", systemImage: "house", value: Tab.home) { ... } -/// Tab(value: Tab.search, role: .search) { ... } +/// Tab("Home", systemImage: "house", value: AppTab.home) { ... } +/// Tab(value: AppTab.search, role: .search) { ... } /// } /// ``` /// - Experiment: This API is in preview and subject to change. @available(iOS 18.0, macOS 15.0, tvOS 18.0, watchOS 11.0, *) -public struct TabContentFlow>: View { +public struct TabContentFlow>: View { @State private var coordinator: Coordinator - @TabContentBuilder private let content: () -> Content + @TabContentBuilder private let content: () -> Content /// - Parameters: /// - coordinator: The instance of the coordinator used as the model and retained as ``SwiftUI.State`` /// - content: The definition of tabs using the ``SwiftUI.Tab`` API. - public init(coordinator: Coordinator, @TabContentBuilder content: @MainActor @escaping () -> Content) { + public init(coordinator: Coordinator, @TabContentBuilder content: @MainActor @escaping () -> Content) { self._coordinator = State(wrappedValue: coordinator) self.content = content } diff --git a/Templates/Tab Coordinator.xctemplate/___VARIABLE_tabCoordinatorIdentifier___TabCoordinator.swift b/Templates/Tab Coordinator.xctemplate/___VARIABLE_tabCoordinatorIdentifier___TabCoordinator.swift index d95a0ab..c5b4b45 100644 --- a/Templates/Tab Coordinator.xctemplate/___VARIABLE_tabCoordinatorIdentifier___TabCoordinator.swift +++ b/Templates/Tab Coordinator.xctemplate/___VARIABLE_tabCoordinatorIdentifier___TabCoordinator.swift @@ -6,35 +6,31 @@ import SwiftUI @Observable final class ___VARIABLE_tabCoordinatorIdentifier___TabCoordinator: @MainActor TabCoordinator { - nonisolated enum Tab { + nonisolated enum AppTab { case firstTab case secondTab } private let container: Container - var selectedTab: Tab + var selectedTab: AppTab var modalCover: ModalCoverModel? - init(container: Container, selectedTab: Tab) { + init(container: Container, selectedTab: AppTab) { self.container = container self.selectedTab = selectedTab } @ViewBuilder static func rootView(with instance: ___VARIABLE_tabCoordinatorIdentifier___TabCoordinator) -> some View { - TabViewFlow(coordinator: instance) { - Text("First Tab") - .tabItem { - Text("First") - } - .tag(Tab.firstTab) - - Text("Second Tab") - .tabItem { - Text("Second") - } - .tag(Tab.secondTab) + TabContentFlow(coordinator: instance) { + Tab("First", systemImage: "1.circle", value: AppTab.firstTab) { + Text("First Tab") + } + + Tab("Second", systemImage: "2.circle", value: AppTab.secondTab) { + Text("Second Tab") + } } } From 22106e061864746d8fc36c64761ad717bd36b457 Mon Sep 17 00:00:00 2001 From: janpollak <40995260+janpollak@users.noreply.github.com> Date: Wed, 20 May 2026 11:12:23 +0200 Subject: [PATCH 2/2] =?UTF-8?q?Fix=20'ment'=20=E2=86=92=20'meant'=20typo?= =?UTF-8?q?=20in=20coordinator=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sources/FuturedArchitecture/Architecture/Coordinator.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/FuturedArchitecture/Architecture/Coordinator.swift b/Sources/FuturedArchitecture/Architecture/Coordinator.swift index 4d4ca78..078472c 100644 --- a/Sources/FuturedArchitecture/Architecture/Coordinator.swift +++ b/Sources/FuturedArchitecture/Architecture/Coordinator.swift @@ -66,7 +66,7 @@ extension Coordinator { } /// `TabCoordinator` provides additional requirements for the use with ``SwiftUI.TabView``. -/// This *coordinator* is ment to have ``TabViewFlow`` (or ``TabContentFlow`` on iOS 18+) as the Root view. +/// This *coordinator* is meant to have ``TabViewFlow`` (or ``TabContentFlow`` on iOS 18+) as the Root view. /// - Experiment: This API is in preview and subject to change. public protocol TabCoordinator: Coordinator { /// The `Hashable` value used to identify the currently selected tab. Matches the `value:` @@ -77,7 +77,7 @@ public protocol TabCoordinator: Coordinator { } /// `NavigationStackCoordinator` provides additional requirements for use with ``SwiftUI.NavigationStack``. -/// This *coordinator* is ment have ``NavigationStackFlow`` as the Root view. +/// This *coordinator* is meant to have ``NavigationStackFlow`` as the Root view. /// /// - ToDo: Create a template for this coordinator. public protocol NavigationStackCoordinator: Coordinator {