{"id":19260615,"url":"https://github.com/evant/nav","last_synced_at":"2025-10-15T01:42:40.064Z","repository":{"id":48002064,"uuid":"319173341","full_name":"evant/nav","owner":"evant","description":"A simple declarative Android compose navigator","archived":false,"fork":false,"pushed_at":"2021-08-11T03:55:44.000Z","size":189,"stargazers_count":7,"open_issues_count":1,"forks_count":2,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-04-16T12:46:43.295Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Kotlin","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/evant.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-12-07T01:40:54.000Z","updated_at":"2024-04-16T12:46:43.296Z","dependencies_parsed_at":"2022-08-12T16:20:34.083Z","dependency_job_id":null,"html_url":"https://github.com/evant/nav","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fnav","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fnav/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fnav/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fnav/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/evant","download_url":"https://codeload.github.com/evant/nav/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223871533,"owners_count":17217571,"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-09T19:22:04.300Z","updated_at":"2025-10-15T01:42:35.028Z","avatar_url":"https://github.com/evant.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Nav\n[![CircleCI](https://circleci.com/gh/evant/nav.svg?style=svg\u0026circle-token=8792fa19911be92d6a1d66dd45ece3bf6712f778)](https://circleci.com/gh/evant/nav)\n[![Sonatype Snapshot](https://img.shields.io/nexus/s/https/oss.sonatype.org/me.tatarka.compose.nav/nav.svg)](https://oss.sonatype.org/content/repositories/snapshots/me/tatarka/compose/nav/)\n\nA simple declarative Android compose navigator\n\n## Nav\n\n### Setup\n\n```kotlin\nrepositories {\n  mavenCentral()\n}\n\ndependencies {\n  implementation(\"me.tatarka.compose.nav:nav:0.1\")\n}\n```\n\n### Usage\n\nThe core component is a `Navigator` that takes a list of pages. The top page will be displayed to\nthe user and pages in the backstack will have their state saved. You can use anything to represent\nyour page state, but I recommend using a sealed class. You should also use `rememberSaveable()` to\nensure the pages are remembered through process death.\n\n```kotlin\nsealed class Page : Parcelable {\n   @Parcelize\n   object List : Page()\n   @Parcelize\n   data class Detail(id: Int): Page()\n}\n\nval pages = rememberSaveable { mutableStateListOf\u003cPage\u003e(Page.List) }\n\nNavigator(pages = pages, onPopPage = { pages.removeLast() }) { page -\u003e\n   when (page) {\n       is List -\u003e ListPage()\n       is Detail -\u003e DetailPage(id = page.id)\n   }\n}\n```\n\nThis allows you to control the back stack however you want. Alternatively, if you want a more \nopinionated way to manipulate the backstack you can use the `BackStack` class. If will enforce a\nstarting destination and you can only push and pop the stack.\n\n```kotlin\nval backStack = rememberSaveable { backStackOf\u003cPage\u003e(Page.List) } \n\nNavigator(backStack) { page -\u003e\n   when (page) {\n       is List -\u003e ListPage()\n       is Detail -\u003e DetailPage(id = page.id)\n   }\n}\n\n...\n\nbackStack.navigate(page = Page.Detail(id = 1)) {\n  popUpTo(singleTop = true) { it is Page.List }\n}\nbackStack.pop()\n```\n\n\n### Animation\n\nWhen transitioning between pages, you can use the `pageTransition` property to animate them. For\nexample, a simple cross-fade can be done with:\n\n```kotlin\nNavigator(backStack) { page -\u003e\n    pageTransition.AnimatedVisibility(\n        visible = { page == it },\n        enter = fadeIn(),\n        exit = fadeOut(),\n    ) {\n        ...\n    }\n}\n```\n\nIf you want to customize the transition per page, you can inspect the `pageTranstion.currentState`\nand `pageTransition.targetState` values which will be the previous and current pages respectively.\nCheck out the sample app to see a more fully-fledged version of this.\n\n```kotlin\nNavigator(backStack) { page -\u003e\n    val current = pageTransition.currentState\n    val next = pageTransition.targetState\n\n    val (exitTransition, enterTransition) = when {\n        current is Page1 \u0026\u0026 next is Page2 -\u003e slideOutLeft() to slideInRight()\n        current is Page2 \u0026\u0026 next is Page1 -\u003e slideOutRight() to slideInLeft()\n        else -\u003e fadeOut() to fadeIn()\n    }\n\n    pageTransition.AnimatedVisibility(\n        visible = { page == it },\n        enter = enterTransition,\n        exit = exitTransition,\n    ) {\n        ...\n    }\n}\n```\n\n## Router (Experimental)\n\n### Usage\n\nYou can annotate sealed class variants with `@Route(\"path\")` and it will generate a `parseRoute()`\nmethod to parse a path into the correct variant.\n\n```kotlin\nsealed class Page : Parcelable {\n   @Parcelize\n   @Route(\"\", root = true)\n   object List : Page()\n   @Parcelize\n   @Route(\"/detail/{id}\")\n   data class Detail(id: Int): Page()\n}\n...\n\nval backStack = backStackOf(parseRoute(deepLink))\n```\n\nA helper is also provided to route your deep link from your activity into your compose tree. It is\nrecommend you set `android:launchMode=\"singleTop\"` in your manifest and override `onNewIntent()`.\nThis ensures your Activity isn't recreated when receiving an intent. \n\n```kotlin\nclass MainActivity : ComponentActivity() {\n    \n    private val deepLinkHandler = DeepLinkHandler(this)\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        setContent {\n            var backStack by rememberSaveableOf { mutableStateOf(backStackOf\u003cPage\u003e(Page.Home)) }\n            deepLinkHandler.OnDeepLink { link -\u003e backStack = backStackOf(parseRoute(link)) }\n            App(backStack)\n        }\n    }\n\n    override fun onNewIntent(intent: Intent?) {\n        deepLinkHandler.onNewIntent(intent)\n    }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevant%2Fnav","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevant%2Fnav","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevant%2Fnav/lists"}