{"id":20325150,"url":"https://github.com/swiftuix/coordinator","last_synced_at":"2025-04-07T11:07:50.835Z","repository":{"id":42497618,"uuid":"262109429","full_name":"SwiftUIX/Coordinator","owner":"SwiftUIX","description":"A declarative navigation API for SwiftUI.","archived":false,"fork":false,"pushed_at":"2024-08-22T05:51:00.000Z","size":106,"stargazers_count":273,"open_issues_count":6,"forks_count":27,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-31T09:06:14.242Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SwiftUIX.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-07T17:00:25.000Z","updated_at":"2025-03-31T08:11:04.000Z","dependencies_parsed_at":"2024-03-15T23:33:25.318Z","dependency_job_id":"bd9524fe-241c-47bf-9b4d-4197ef125578","html_url":"https://github.com/SwiftUIX/Coordinator","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftUIX%2FCoordinator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftUIX%2FCoordinator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftUIX%2FCoordinator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftUIX%2FCoordinator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SwiftUIX","download_url":"https://codeload.github.com/SwiftUIX/Coordinator/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247640463,"owners_count":20971557,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-14T19:38:55.007Z","updated_at":"2025-04-07T11:07:50.811Z","avatar_url":"https://github.com/SwiftUIX.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Concepts\n\nThis framework uses three main concepts:\n\n- **Route** - an identifiable value that represents a destination in your app \n- **Transition** - a visual transition to be applied on a view \n- **Coordinator** - an object that maps **routes** to **transitions** and applies it on the current view hierarchy.\n\n# Getting Started \n\n## Basics\n\n### Definite a set of destinations\n\nA destination could be a screen, a modal or even a dismiss action. Destinations are typically represented via `enum`s.\n\n```swift\nenum AppDestination {\n    case first\n    case second\n    case third\n}\n```\n\n### Define a coordinator\n\nThere are three steps to defining a coordinator:\n\n1. You must subclass either `UIViewControllerCoordinator` or `AppKitOrUIKitWindowCoordinator`\n2. You must parametrize your subclass with a **route**.\n3. You must override and implement the function `transition(for:)`, which is responsible for mapping a **route** to a **transition**.\n\n```swift\nclass AppCoordinator: AppKitOrUIKitWindowCoordinator\u003cAppDestination\u003e {\n    override func transition(for route: AppDestination) -\u003e ViewTransition {\n        switch route {\n            case .first:\n                return .present(Text(\"First\"))\n            case .second:\n                return .push(Text(\"Second\"))\n            case .third:\n                return .set(Text(\"third\"))\n        }\n    }\n}\n```\n\n### Integrate your coordinator\n\nCoordinators can be integrated in a fashion similar to `@EnvironmentObject`. For this example, we'll create an instance of the `AppCoordinator` defined in the previous section, and pass it to a `ContentView` via the `View/coordinator(_:)` function.\n\n`ContentView` uses the coordinator via a special property wrapper, `@Coordinator`, which gives access to the nearest available coordinator for a given route type at runtime (in this case, `AppCoordinator`).\n\n```swift\n@main\nstruct App: SwiftUI.App {\n    @StateObject var coordinator = AppCoordinator()\n    \n    var body: some Scene {\n        WindowGroup {\n            NavigationView {\n                ContentView()\n                    .coordinator(coordinator)\n            }\n        }\n    }\n}\n\nstruct ContentView: View {\n    @Coordinator(for: AppDestination.self) var coordinator\n    \n    var body: some View {\n        VStack {\n            Button(\"First\") {\n                coordinator.trigger(.first)\n            }\n            \n            Button(\"Second\") {\n                coordinator.trigger(.second)\n            }\n            \n            Button(\"Third\") {\n                coordinator.trigger(.third)\n            }\n        }\n    }\n}\n```\n\n## Ad-hoc Coordinators\n\nIf you wish to provide a scoped coordinator for a child view in SwiftUI, you can use `View.coordinate` to create an ad-hoc coordinator.\n\n```swift\nstruct ContentView: View {\n    private enum MyRoute {\n        case foo\n        case bar\n    }\n\n    var body: some View {\n        NavigationView {\n            ChildView()\n        }\n        .coordinate(MyRoute.self) { route in\n            switch route {\n                case .foo:\n                    return .push(Text(\"Foo\"))\n                case .bar:\n                    return .present(Text(\"Bar\"))\n            }\n        }\n    }\n\n    private struct ChildView: View {\n        @Coordinator(for: MyRoute.self) var coordinator\n\n        var body: some View {\n            VStack {\n                Button(\"Foo\") {\n                    coordinator.trigger(.foo)\n                }\n\n                Button(\"Bar\") {\n                    coordinator.trigger(.bar)\n                }\n            }\n        }\n    }\n}\n```\n\nIn this example `ContentView` creates an ad-hoc coordinator via `.coordinate(MyRoute.self) { .. }` and provides it to a `NavigationView` containing `ChildView`. \n\n`ChildView` can now access this coordinator using the `@Coordinator` property wrapper referencing the route type `MyRoute` declared inside `ContentView`. \n\nIn this example, only `ContentView` and types defined within its namespace can access `MyRoute` as it is marked as a private `enum`. It is good practice to scope your routes tightly wherever possible, as it allows you to reason about your navigation flows in a simpler way.\n\n## Custom Transitions\n\nIf you need lower level access to the underlying `UIViewController ` or `UIWindow`, use `ViewTransition.custom` to implement a custom transition.\n\nIn the following example, `MyRoute.foo` is implemented via a standard `ViewTransition` whereas `MyRoute.bar` is implemented as a custom one.\n\n```swift\nimport Coordinator\nimport UIKit\n\nenum MyRoute {\n    case foo\n    case bar\n}\n\nclass MyViewCoordinator: UIViewControllerCoordinator\u003cMyRoute\u003e {\n    override func transition(for route: MyRoute) -\u003e ViewTransition {\n        switch route {\n            case .foo:\n                return .present(Text(\"Foo\"))\n            case .bar:\n                return .custom {\n                    guard let rootViewController = self.rootViewController else {\n                        return assertionFailure()\n                    }\n\n                    // Use `rootViewController` to perform a custom transition.\n                    rootViewController.present(\n                        UIViewController(),\n                        animated: true,\n                        completion: { }\n                    )\n                }\n        }\n    }\n}\n```\n\n**Note:** Refrain from adding side-effects or business logic to your custom transition block. A `ViewCoordinator` is only supposed to handle transitions. Adding anything beyond transition logic breaks the conceptual model of a coordinator.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswiftuix%2Fcoordinator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fswiftuix%2Fcoordinator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswiftuix%2Fcoordinator/lists"}