{"id":20639216,"url":"https://github.com/alexdremov/pathpresenter","last_synced_at":"2026-03-04T09:02:12.031Z","repository":{"id":49348422,"uuid":"517418740","full_name":"alexdremov/PathPresenter","owner":"alexdremov","description":"Pure SwiftUI state-driven library to present view sequences and hierarchies.","archived":false,"fork":false,"pushed_at":"2023-05-10T19:35:20.000Z","size":33,"stargazers_count":73,"open_issues_count":0,"forks_count":3,"subscribers_count":5,"default_branch":"main","last_synced_at":"2026-01-30T22:56:58.447Z","etag":null,"topics":["architecture","ios","ios-swift","ios-ui","mvvm","routing","swift","swift-package-manager","swift-ui","swiftui","swiftui-animations","swiftui-demo","swiftui-example","swiftui-framework"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alexdremov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2022-07-24T19:32:08.000Z","updated_at":"2025-04-08T08:54:10.000Z","dependencies_parsed_at":"2023-02-06T19:15:46.695Z","dependency_job_id":null,"html_url":"https://github.com/alexdremov/PathPresenter","commit_stats":{"total_commits":23,"total_committers":2,"mean_commits":11.5,"dds":0.04347826086956519,"last_synced_commit":"ae353eae4b18e7961b767b30fa2af76a9fd40eb6"},"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/alexdremov/PathPresenter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexdremov%2FPathPresenter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexdremov%2FPathPresenter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexdremov%2FPathPresenter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexdremov%2FPathPresenter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alexdremov","download_url":"https://codeload.github.com/alexdremov/PathPresenter/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexdremov%2FPathPresenter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30076935,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-04T08:01:56.766Z","status":"ssl_error","status_checked_at":"2026-03-04T08:00:42.919Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["architecture","ios","ios-swift","ios-ui","mvvm","routing","swift","swift-package-manager","swift-ui","swiftui","swiftui-animations","swiftui-demo","swiftui-example","swiftui-framework"],"created_at":"2024-11-16T15:23:00.704Z","updated_at":"2026-03-04T09:02:12.017Z","avatar_url":"https://github.com/alexdremov.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PathPresenter\n![GitHub release (latest by date)](https://img.shields.io/github/v/release/AlexRoar/PathPresenter)\n![GitHub top language](https://img.shields.io/github/languages/top/AlexRoar/PathPresenter)\n[![Codacy Badge](https://app.codacy.com/project/badge/Grade/054cef3e06ed4bf69725db51a81e1c1b)](https://www.codacy.com/gh/AlexRoar/PathPresenter/dashboard?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=AlexRoar/PathPresenter\u0026amp;utm_campaign=Badge_Grade)\n\n\nhttps://user-images.githubusercontent.com/25539425/181922855-3ff3aa77-757b-4091-b682-63456fe963a1.mp4\n\n\nPure SwiftUI routing with transitions, animations, and `.sheet()` support.\n\nIn SwiftUI, View is a function of the state. Routing is not an exception. Reasoning and under the hood explanation can be found on my blog: \n\nhttp://alexdremov.me/swiftui-navigation-is-a-mess-heres-what-you-can-do/\n\n## Why\n- `.sheet()` usages are usually messy, deviate from app architecture, and require additional business-logic\n- Creating view sequences in SwiftUI is not elegant\n- MVVM is gorgeous, but what about one level above? Routing between MVVM modules is cluttered.\n\n## Advantages\n- **Purely state-driven**.\nNo ObservableObjects, no EnvironmentObjects, no Singletons.\n- **Pure SwiftUI**.\n- **SwiftUI transitions and animations**.\n- **Structured `.sheet()` support**.\nNo need to remaster the whole codebase to present the view with `.sheet()`. It just works.\n\n## Example\n\nExample from the video: [PathPresenterExample](https://github.com/AlexRoar/PathPresenterExample/tree/main)\n\nThe view hierarchy is managed through the `PathPresenter.Path()` structure.\nYou can push new views into it using `.append` methods and delete views from the top using `.removeLatest`.\n\nInternally, the view's layout is managed by `ZStack`, so all views history is visible.\n\nPossible presentation ways:\n```swift\nenum PathType {\n  /**\n   * Just show a view. No animation, no transition.\n   * Show view above all other views\n   */\n  case plain\n  \n  /**\n   * Show view with in and out transitions.\n   * Transition animation also can be specified.\n   */\n  case animated(transition: AnyTransition, animation: Animation)\n  \n  /**\n   * Show view in .sheet()\n   * - Note: If you want to present several views in sheet,\n   * you can create a second RoutingView and use it in sheet!\n   */\n  case sheet(onDismiss: Action)\n}\n```\n\nComplete example:\n\n\u003chr\u003e\n\u003cimg width=\"800\" src=\"https://i.ibb.co/9ydVzgG/ezgif-com-gif-maker-5.gif\"\u003e\n\n```swift\nstruct RootViewGitHub: View {\n    @State var path = PathPresenter.Path()\n\n    var body: some View {\n        PathPresenter.RoutingView(path: $path) {\n            // Root view. Always presented\n            VStack {\n                Button(\"Push\") {\n                    path.append(\n                        VStack {\n                            Text(\"Hello from plain push\")\n                            backButton\n                        }.frame(width: 300, height: 300)\n                         .background(.white)\n                         .border(.red),\n                        type: .plain\n                    )\n                }\n                Button(\"Sheet\") {\n                    path.append(\n                        VStack {\n                            Text(\"Hello from sheet\")\n                            backButton\n                        }.frame(width: 300, height: 300)\n                         .background(.white)\n                         .border(.red),\n                        type: .sheet(onDismiss: {print(\"dismissed\")})\n                    )\n                }\n                Button(\"Left animation\") {\n                    path.append(\n                        VStack {\n                            Text(\"Hello from left animation\")\n                            backButton\n                        }.frame(width: 300, height: 300)\n                         .background(.white)\n                         .border(.red),\n                        type: .animated(transition: .move(edge: .leading),\n                                        animation: .easeIn)\n                    )\n                }\n            }\n            .frame(width: 300, height: 300)\n        }\n    }\n    \n    var backButton: some View {\n        Button(\"Back\") {\n            if !path.isEmpty {\n                path.removeLast()\n            }\n        }\n    }\n}\n```\n\u003chr\u003e\n\n## Transitions and animation example\n\u003cimg width=900 src=\"https://i.ibb.co/NVwcQp5/ezgif-com-gif-maker-4.gif\"\u003e\n\n## Documentation\n\nCode is mostly commented and simply structured. Check it out! \n\n## TODO\n- **Path-based routing**. Define view hierarchy with URL-like structures for better views switching architecture\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexdremov%2Fpathpresenter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falexdremov%2Fpathpresenter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexdremov%2Fpathpresenter/lists"}