{"id":13995021,"url":"https://github.com/johnpatrickmorgan/NavigationBackport","last_synced_at":"2025-07-22T21:31:46.405Z","repository":{"id":37212302,"uuid":"502206806","full_name":"johnpatrickmorgan/NavigationBackport","owner":"johnpatrickmorgan","description":"Backported SwiftUI navigation APIs introduced in WWDC22","archived":false,"fork":false,"pushed_at":"2024-10-15T13:26:07.000Z","size":212,"stargazers_count":868,"open_issues_count":4,"forks_count":53,"subscribers_count":13,"default_branch":"main","last_synced_at":"2024-11-28T20:50:02.201Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/johnpatrickmorgan.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":"2022-06-10T23:38:01.000Z","updated_at":"2024-11-26T07:32:35.000Z","dependencies_parsed_at":"2024-05-14T09:47:35.452Z","dependency_job_id":"341327f0-61ab-4286-a0b6-b9bd18432a5a","html_url":"https://github.com/johnpatrickmorgan/NavigationBackport","commit_stats":{"total_commits":47,"total_committers":4,"mean_commits":11.75,"dds":"0.21276595744680848","last_synced_commit":"88437a4bd67dc2c0222d8def073d0eb3a38a844a"},"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnpatrickmorgan%2FNavigationBackport","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnpatrickmorgan%2FNavigationBackport/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnpatrickmorgan%2FNavigationBackport/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnpatrickmorgan%2FNavigationBackport/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/johnpatrickmorgan","download_url":"https://codeload.github.com/johnpatrickmorgan/NavigationBackport/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227177734,"owners_count":17743152,"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-08-09T14:03:13.003Z","updated_at":"2024-11-29T17:30:51.898Z","avatar_url":"https://github.com/johnpatrickmorgan.png","language":"Swift","funding_links":["https://ko-fi.com/T6T114GWOT"],"categories":["Swift"],"sub_categories":[],"readme":"# Navigation Backport\n\nThis package uses the navigation APIs available in older SwiftUI versions (such as `NavigationView` and `NavigationLink`) to recreate the new `NavigationStack` APIs introduced in WWDC22, so that you can start targeting those APIs on older versions of iOS, tvOS, macOS and watchOS. When running on an OS version that supports `NavigationStack`, `NavigationStack` will be used under the hood.\n \n✅ `NavigationStack` -\u003e `NBNavigationStack`\n\n✅ `NavigationLink` -\u003e `NBNavigationLink`\n\n✅ `NavigationPath` -\u003e `NBNavigationPath`\n\n✅ `navigationDestination` -\u003e `nbNavigationDestination`\n\n✅ `NavigationPath.CodableRepresentation` -\u003e `NBNavigationPath.CodableRepresentation`\n\n\nYou can migrate to these APIs now, and when you eventually bump your deployment target, you can remove this library and easily migrate to its SwiftUI equivalent. `NavigationStack`'s full API is replicated, so you can initialise an `NBNavigationStack` with a binding to an `Array`, with a binding to an `NBNavigationPath` binding, or with no binding at all.\n\n## Example\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick to expand an example\u003c/summary\u003e\n\n```swift\nimport NavigationBackport\nimport SwiftUI\n\nstruct ContentView: View {\n  @State var path = NBNavigationPath()\n\n  var body: some View {\n    NBNavigationStack(path: $path) {\n      HomeView()\n        .nbNavigationDestination(for: NumberList.self, destination: { numberList in\n          NumberListView(numberList: numberList)\n        })\n        .nbNavigationDestination(for: Int.self, destination: { number in\n          NumberView(number: number)\n        })\n        .nbNavigationDestination(for: EmojiVisualisation.self, destination: { visualisation in\n          EmojiView(visualisation: visualisation)\n        })\n    }\n  }\n}\n\nstruct HomeView: View {\n  var body: some View {\n    VStack(spacing: 8) {\n      NBNavigationLink(value: NumberList(range: 0 ..\u003c 100), label: { Text(\"Pick a number\") })\n    }.navigationTitle(\"Home\")\n  }\n}\n\nstruct NumberList: Hashable {\n  let range: Range\u003cInt\u003e\n}\n\nstruct NumberListView: View {\n  let numberList: NumberList\n  var body: some View {\n    List {\n      ForEach(numberList.range, id: \\.self) { number in\n        NBNavigationLink(\"\\(number)\", value: number)\n      }\n    }.navigationTitle(\"List\")\n  }\n}\n\nstruct NumberView: View {\n  @EnvironmentObject var navigator: PathNavigator\n  \n  let number: Int\n\n  var body: some View {\n    VStack(spacing: 8) {\n      Text(\"\\(number)\")\n      NBNavigationLink(\n        value: number + 1,\n        label: { Text(\"Show next number\") }\n      )\n      NBNavigationLink(\n        value: EmojiVisualisation(emoji: \"🐑\", count: number),\n        label: { Text(\"Visualise with sheep\") }\n      )\n      Button(\"Go back to root\", action: { navigator.popToRoot() })\n    }.navigationTitle(\"\\(number)\")\n  }\n}\n\nstruct EmojiVisualisation: Hashable {\n  let emoji: String\n  let count: Int\n  \n  var text: String {\n    Array(repeating: emoji, count: count).joined()\n  }\n}\n\nstruct EmojiView: View {\n  let visualisation: EmojiVisualisation\n\n  var body: some View {\n    Text(visualisation.text)\n      .navigationTitle(\"Visualise \\(visualisation.count)\")\n  }\n}\n```\n\n\u003c/details\u003e\n\n## Additional features\n\nAs well as replicating the standard features of the new `NavigationStack` APIs, some helpful utilities have also been added. \n\n### Navigator\n\nA `Navigator` object is available through the environment, giving access to the current navigation path. The navigator can be accessed via the environment, e.g. for a NBNavigationPath-backed stack:\n\n```swift\n@EnvironmentObject var navigator: PathNavigator\n```\n\nOr for a stack backed by an Array, e.g. `[ScreenType]`:\n\n```swift\n@EnvironmentObject var navigator: Navigator\u003cScreenType\u003e\n```\n\nAs well as allowing you to inspect the path elements, the navigator can be used to push new screens, pop, pop to a specific screen or pop to the root.\n\n### Navigation functions\n\nWhether interacting with an `Array`, an `NBNavigationPath`, or a `Navigator`, a number of utility functions are available for easier navigation, such as:\n\n```swift\npath.push(Profile(name: \"John\"))\n\npath.pop()\n\npath.popToRoot()\n\npath.popTo(Profile.self)\n```\n\nNote that, if you want to use these methods on an `Array`, ensure the `Array`'s `Element` conforms to `NBScreen`, a protocol that inherits from Hashable without adding any additional requirements. This avoids polluting all arrays with APIs specific to navigation.\n\n## Deep-linking\n \n Before `NavigationStack`, SwiftUI did not support pushing more than one screen in a single state update, e.g. when deep-linking to a screen multiple layers deep in a navigation hierarchy. `NavigationBackport` works around this limitation: you can make any such path changes, and the library will, behind the scenes, break down the larger update into a series of smaller updates that SwiftUI supports if necessary, with delays in between. For example, the following code that pushes three screens in one state update will push the screens one by one if needed:\n\n```swift\n  path.append(Screen.orders)\n  path.append(Screen.editOrder(id: id))\n  path.append(Screen.confirmChanges(orderId: id))\n```\n\nThis only happens when necessary: on versions of SwiftUI that support `NavigationStack`, all three screens will be pushed successfully in one update.\n\n## Support for iOS/tvOS 13\n\nThis library targets iOS/tvOS versions 14 and above, since it uses `StateObject`, which is unavailable on iOS/tvOS 13. However, there is an `ios13` branch, which uses [SwiftUIBackports](https://github.com/shaps80/SwiftUIBackports)' backported StateObject, so that it works on iOS/tvOS 13 too.\n\n## FlowStacks\n\nWant to further upgrade your navigation APIs? [FlowStacks](https://github.com/johnpatrickmorgan/FlowStacks) enhances these familiar APIs to allow you to additionally drive sheet and full-screen cover navigation from a single unified interface. \n\n-------\n\n[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/T6T114GWOT)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohnpatrickmorgan%2FNavigationBackport","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohnpatrickmorgan%2FNavigationBackport","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohnpatrickmorgan%2FNavigationBackport/lists"}