Repository: arkivanov/Decompose
Pull request #136 (2022-07-09 15:19:18)

Renamed RouterState to ChildStack
As part of #134 


Patch:
diff --git a/decompose/api/android/decompose.api b/decompose/api/android/decompose.api
index 4fa30ae6..d566058d 100644
--- a/decompose/api/android/decompose.api
+++ b/decompose/api/android/decompose.api
@@ -115,28 +115,29 @@ public final class com/arkivanov/decompose/router/RouterState {
 	public fun toString ()Ljava/lang/String;
 }
 
-public final class com/arkivanov/decompose/router/stack/RouterFactoryKt {
-	public static final fun stackRouter (Lcom/arkivanov/decompose/ComponentContext;Lkotlin/jvm/functions/Function0;Lkotlin/reflect/KClass;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lcom/arkivanov/decompose/router/stack/StackRouter;
-	public static synthetic fun stackRouter$default (Lcom/arkivanov/decompose/ComponentContext;Lkotlin/jvm/functions/Function0;Lkotlin/reflect/KClass;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/arkivanov/decompose/router/stack/StackRouter;
-}
-
-public final class com/arkivanov/decompose/router/stack/RouterState {
+public final class com/arkivanov/decompose/router/stack/ChildStack {
 	public fun <init> (Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;)V
 	public synthetic fun <init> (Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
 	public fun <init> (Ljava/lang/Object;Ljava/lang/Object;)V
 	public final fun component1 ()Lcom/arkivanov/decompose/Child$Created;
 	public final fun component2 ()Ljava/util/List;
-	public final fun copy (Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;)Lcom/arkivanov/decompose/router/stack/RouterState;
-	public static synthetic fun copy$default (Lcom/arkivanov/decompose/router/stack/RouterState;Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;ILjava/lang/Object;)Lcom/arkivanov/decompose/router/stack/RouterState;
+	public final fun copy (Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;)Lcom/arkivanov/decompose/router/stack/ChildStack;
+	public static synthetic fun copy$default (Lcom/arkivanov/decompose/router/stack/ChildStack;Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;ILjava/lang/Object;)Lcom/arkivanov/decompose/router/stack/ChildStack;
 	public fun equals (Ljava/lang/Object;)Z
 	public final fun getActive ()Lcom/arkivanov/decompose/Child$Created;
 	public final fun getBackStack ()Ljava/util/List;
+	public final fun getItems ()Ljava/util/List;
 	public fun hashCode ()I
 	public fun toString ()Ljava/lang/String;
 }
 
+public final class com/arkivanov/decompose/router/stack/RouterFactoryKt {
+	public static final fun stackRouter (Lcom/arkivanov/decompose/ComponentContext;Lkotlin/jvm/functions/Function0;Lkotlin/reflect/KClass;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lcom/arkivanov/decompose/router/stack/StackRouter;
+	public static synthetic fun stackRouter$default (Lcom/arkivanov/decompose/ComponentContext;Lkotlin/jvm/functions/Function0;Lkotlin/reflect/KClass;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/arkivanov/decompose/router/stack/StackRouter;
+}
+
 public abstract interface class com/arkivanov/decompose/router/stack/StackRouter {
-	public abstract fun getState ()Lcom/arkivanov/decompose/value/Value;
+	public abstract fun getStack ()Lcom/arkivanov/decompose/value/Value;
 	public abstract fun navigate (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)V
 }
 
diff --git a/decompose/api/jvm/decompose.api b/decompose/api/jvm/decompose.api
index 5b2dd755..79e0a0ad 100644
--- a/decompose/api/jvm/decompose.api
+++ b/decompose/api/jvm/decompose.api
@@ -102,28 +102,29 @@ public final class com/arkivanov/decompose/router/RouterState {
 	public fun toString ()Ljava/lang/String;
 }
 
-public final class com/arkivanov/decompose/router/stack/RouterFactoryKt {
-	public static final fun stackRouter (Lcom/arkivanov/decompose/ComponentContext;Lkotlin/jvm/functions/Function0;Lkotlin/reflect/KClass;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lcom/arkivanov/decompose/router/stack/StackRouter;
-	public static synthetic fun stackRouter$default (Lcom/arkivanov/decompose/ComponentContext;Lkotlin/jvm/functions/Function0;Lkotlin/reflect/KClass;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/arkivanov/decompose/router/stack/StackRouter;
-}
-
-public final class com/arkivanov/decompose/router/stack/RouterState {
+public final class com/arkivanov/decompose/router/stack/ChildStack {
 	public fun <init> (Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;)V
 	public synthetic fun <init> (Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
 	public fun <init> (Ljava/lang/Object;Ljava/lang/Object;)V
 	public final fun component1 ()Lcom/arkivanov/decompose/Child$Created;
 	public final fun component2 ()Ljava/util/List;
-	public final fun copy (Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;)Lcom/arkivanov/decompose/router/stack/RouterState;
-	public static synthetic fun copy$default (Lcom/arkivanov/decompose/router/stack/RouterState;Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;ILjava/lang/Object;)Lcom/arkivanov/decompose/router/stack/RouterState;
+	public final fun copy (Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;)Lcom/arkivanov/decompose/router/stack/ChildStack;
+	public static synthetic fun copy$default (Lcom/arkivanov/decompose/router/stack/ChildStack;Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;ILjava/lang/Object;)Lcom/arkivanov/decompose/router/stack/ChildStack;
 	public fun equals (Ljava/lang/Object;)Z
 	public final fun getActive ()Lcom/arkivanov/decompose/Child$Created;
 	public final fun getBackStack ()Ljava/util/List;
+	public final fun getItems ()Ljava/util/List;
 	public fun hashCode ()I
 	public fun toString ()Ljava/lang/String;
 }
 
+public final class com/arkivanov/decompose/router/stack/RouterFactoryKt {
+	public static final fun stackRouter (Lcom/arkivanov/decompose/ComponentContext;Lkotlin/jvm/functions/Function0;Lkotlin/reflect/KClass;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lcom/arkivanov/decompose/router/stack/StackRouter;
+	public static synthetic fun stackRouter$default (Lcom/arkivanov/decompose/ComponentContext;Lkotlin/jvm/functions/Function0;Lkotlin/reflect/KClass;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/arkivanov/decompose/router/stack/StackRouter;
+}
+
 public abstract interface class com/arkivanov/decompose/router/stack/StackRouter {
-	public abstract fun getState ()Lcom/arkivanov/decompose/value/Value;
+	public abstract fun getStack ()Lcom/arkivanov/decompose/value/Value;
 	public abstract fun navigate (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;)V
 }
 
diff --git a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/ChildStack.kt b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/ChildStack.kt
new file mode 100644
index 00000000..72b30733
--- /dev/null
+++ b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/ChildStack.kt
@@ -0,0 +1,32 @@
+package com.arkivanov.decompose.router.stack
+
+import com.arkivanov.decompose.Child
+
+data class ChildStack<out C : Any, out T : Any>(
+    val active: Child.Created<C, T>,
+    val backStack: List<Child<C, T>> = emptyList(),
+) {
+
+    constructor(configuration: C, instance: T) : this(
+        active = Child.Created(
+            configuration = configuration,
+            instance = instance
+        ),
+    )
+
+    val items: List<Child<C, T>> = Items(active = active, backStack = backStack)
+
+    private class Items<C : Any, T : Any>(
+        private val active: Child.Created<C, T>,
+        private val backStack: List<Child<C, T>> = emptyList(),
+    ) : AbstractList<Child<C, T>>() {
+        override val size: Int get() = backStack.size + 1
+
+        override fun get(index: Int): Child<C, T> =
+            when {
+                (index < 0) || (index >= size) -> throw IndexOutOfBoundsException("Index is out of bounds: index=$index, size=$size")
+                index < backStack.size -> backStack[index]
+                else -> active
+            }
+    }
+}
diff --git a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/RouterState.kt b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/RouterState.kt
deleted file mode 100644
index c0ff5174..00000000
--- a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/RouterState.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.arkivanov.decompose.router.stack
-
-import com.arkivanov.decompose.Child
-
-data class RouterState<out C : Any, out T : Any>(
-    val active: Child.Created<C, T>,
-    val backStack: List<Child<C, T>> = emptyList(),
-) {
-    constructor(configuration: C, instance: T) : this(
-        active = Child.Created(
-            configuration = configuration,
-            instance = instance
-        ),
-    )
-}
diff --git a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackRouter.kt b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackRouter.kt
index 55d604ec..2b3903a2 100644
--- a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackRouter.kt
+++ b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackRouter.kt
@@ -7,7 +7,7 @@ interface StackRouter<C : Any, out T : Any> {
     /**
      * Returns the current stack of components, which can also be observed for changes
      */
-    val state: Value<RouterState<C, T>>
+    val stack: Value<ChildStack<C, T>>
 
     /**
      * Transforms the current stack of configurations into a new one.
diff --git a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackRouterExt.kt b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackRouterExt.kt
index f7c4305a..2198fe64 100644
--- a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackRouterExt.kt
+++ b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackRouterExt.kt
@@ -78,4 +78,4 @@ fun <C : Any> StackRouter<C, *>.bringToFront(configuration: C, onComplete: () ->
     )
 }
 
-val <C : Any, T : Any> StackRouter<C, T>.activeChild: Child.Created<C, T> get() = state.value.active
+val <C : Any, T : Any> StackRouter<C, T>.activeChild: Child.Created<C, T> get() = stack.value.active
diff --git a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackRouterImpl.kt b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackRouterImpl.kt
index e0e5f8ed..30cbd6e8 100644
--- a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackRouterImpl.kt
+++ b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/stack/StackRouterImpl.kt
@@ -21,7 +21,7 @@ internal class StackRouterImpl<C : Any, T : Any>(
     }
 
     private val onBackPressedHandler = ::onBackPressed
-    override val state: MutableValue<RouterState<C, T>> = MutableValue(stackHolder.stack.toState())
+    override val stack: MutableValue<ChildStack<C, T>> = MutableValue(stackHolder.stack.toState())
     private val queue = SerializedQueue(::navigateActual)
 
     init {
@@ -41,7 +41,7 @@ internal class StackRouterImpl<C : Any, T : Any>(
         val oldStack = stackHolder.stack
         val newStack = navigator.navigate(oldStack = oldStack, transformer = item.transformer)
         stackHolder.stack = newStack
-        state.value = newStack.toState()
+        stack.value = newStack.toState()
         item.onComplete(newStack.configurationStack, oldStack.configurationStack)
     }
 
@@ -57,13 +57,13 @@ internal class StackRouterImpl<C : Any, T : Any>(
             else -> false
         }
 
-    private fun RouterStack<C, T>.toState(): RouterState<C, T> =
-        RouterState(
+    private fun RouterStack<C, T>.toState(): ChildStack<C, T> =
+        ChildStack(
             active = Child.Created(configuration = active.configuration, instance = active.instance),
-            backStack = backStack.map { it.toRouterStateEntry() }
+            backStack = backStack.map { it.toChild() }
         )
 
-    private fun RouterEntry<C, T>.toRouterStateEntry(): Child<C, T> =
+    private fun RouterEntry<C, T>.toChild(): Child<C, T> =
         when (this) {
             is RouterEntry.Created -> Child.Created(configuration = configuration, instance = instance)
             is RouterEntry.Destroyed -> Child.Destroyed(configuration = configuration)
diff --git a/decompose/src/jsMain/kotlin/com/arkivanov/decompose/router/stack/webhistory/DefaultWebHistoryController.kt b/decompose/src/jsMain/kotlin/com/arkivanov/decompose/router/stack/webhistory/DefaultWebHistoryController.kt
index d0ef5419..9beee98d 100644
--- a/decompose/src/jsMain/kotlin/com/arkivanov/decompose/router/stack/webhistory/DefaultWebHistoryController.kt
+++ b/decompose/src/jsMain/kotlin/com/arkivanov/decompose/router/stack/webhistory/DefaultWebHistoryController.kt
@@ -2,7 +2,7 @@ package com.arkivanov.decompose.router.stack.webhistory
 
 import com.arkivanov.decompose.ExperimentalDecomposeApi
 import com.arkivanov.decompose.router.findFirstDifferentIndex
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 import com.arkivanov.decompose.router.stack.StackRouter
 import com.arkivanov.decompose.router.stack.navigate
 import com.arkivanov.decompose.router.startsWith
@@ -23,7 +23,7 @@ class DefaultWebHistoryController internal constructor(
         getConfiguration: (path: String) -> C,
     ) {
         val impl = Impl(router, window, getPath, getConfiguration)
-        router.state.subscribe(impl::onStateChanged)
+        router.stack.subscribe(impl::onStackChanged)
         window.onPopState = impl::onPopState
     }
 
@@ -36,47 +36,47 @@ class DefaultWebHistoryController internal constructor(
         private var isStateObserverFirstPass = true
         private var isStateObserverEnabled = true
 
-        fun onStateChanged(newState: RouterState<C, *>, oldState: RouterState<C, *>) {
+        fun onStackChanged(newStack: ChildStack<C, *>, oldStack: ChildStack<C, *>) {
             if (!isStateObserverEnabled) {
                 return
             }
 
-            val newStack = newState.configurations()
-            val oldStack = oldState.configurations()
-            val firstDifferentIndex = oldStack.findFirstDifferentIndex(newStack)
+            val newConfigurationStack = newStack.configurations()
+            val oldConfigurationStack = oldStack.configurations()
+            val firstDifferentIndex = oldConfigurationStack.findFirstDifferentIndex(newConfigurationStack)
 
             when {
                 // Initialize the history
                 isStateObserverFirstPass -> {
                     isStateObserverFirstPass = false
-                    window.history.replaceState(newStack[0])
-                    for (i in 1..newStack.lastIndex) {
-                        window.history.pushState(newStack[i])
+                    window.history.replaceState(newConfigurationStack[0])
+                    for (i in 1..newConfigurationStack.lastIndex) {
+                        window.history.pushState(newConfigurationStack[i])
                     }
                 }
 
-                newStack == oldStack -> return
+                newConfigurationStack == oldConfigurationStack -> return
 
                 // One or more configurations were popped from the stack
-                oldStack.startsWith(newStack) -> { // Pop removed pages from the history
-                    window.history.go(delta = newStack.size - oldStack.size)
+                oldConfigurationStack.startsWith(newConfigurationStack) -> { // Pop removed pages from the history
+                    window.history.go(delta = newConfigurationStack.size - oldConfigurationStack.size)
                 }
 
                 // One or more configurations were pushed to the history
-                newStack.startsWith(oldStack) -> { // Push new pages to the history
-                    for (i in oldStack.size..newStack.lastIndex) {
-                        window.history.pushState(newStack[i])
+                newConfigurationStack.startsWith(oldConfigurationStack) -> { // Push new pages to the history
+                    for (i in oldConfigurationStack.size..newConfigurationStack.lastIndex) {
+                        window.history.pushState(newConfigurationStack[i])
                     }
                 }
 
                 // The active configuration was changed, and new configurations could be pushed
-                firstDifferentIndex == oldStack.lastIndex -> {
+                firstDifferentIndex == oldConfigurationStack.lastIndex -> {
                     // Replace the current page with a new one
-                    window.history.replaceState(newStack[firstDifferentIndex])
+                    window.history.replaceState(newConfigurationStack[firstDifferentIndex])
 
                     // Push the rest of the pages to the history
-                    for (i in (firstDifferentIndex + 1)..newStack.lastIndex) {
-                        window.history.pushState(newStack[i])
+                    for (i in (firstDifferentIndex + 1)..newConfigurationStack.lastIndex) {
+                        window.history.pushState(newConfigurationStack[i])
                     }
                 }
 
@@ -86,13 +86,13 @@ class DefaultWebHistoryController internal constructor(
                         window.onPopState = ::onPopState
 
                         // Push new pages to the history
-                        for (i in firstDifferentIndex..newStack.lastIndex) {
-                            window.history.pushState(newStack[i])
+                        for (i in firstDifferentIndex..newConfigurationStack.lastIndex) {
+                            window.history.pushState(newConfigurationStack[i])
                         }
                     }
 
                     // Pop removed pages from the history
-                    window.history.go(delta = firstDifferentIndex - oldStack.size)
+                    window.history.go(delta = firstDifferentIndex - oldConfigurationStack.size)
                 }
 
                 // All configurations were popped, and one or more configurations were pushed
@@ -101,17 +101,17 @@ class DefaultWebHistoryController internal constructor(
                         window.onPopState = ::onPopState
 
                         // Replace the current page with a new one
-                        window.history.replaceState(newStack[firstDifferentIndex])
+                        window.history.replaceState(newConfigurationStack[firstDifferentIndex])
 
                         // Push the rest of the pages to the history
                         // Corner case: if there is nothing to push, old pages will remain in the history
-                        for (i in (firstDifferentIndex + 1)..newStack.lastIndex) {
-                            window.history.pushState(newStack[i])
+                        for (i in (firstDifferentIndex + 1)..newConfigurationStack.lastIndex) {
+                            window.history.pushState(newConfigurationStack[i])
                         }
                     }
 
                     // Pop removed pages from the history, except the first one
-                    window.history.go(delta = -oldStack.lastIndex)
+                    window.history.go(delta = -oldConfigurationStack.lastIndex)
                 }
             }
         }
diff --git a/decompose/src/jsMain/kotlin/com/arkivanov/decompose/router/stack/webhistory/Utils.kt b/decompose/src/jsMain/kotlin/com/arkivanov/decompose/router/stack/webhistory/Utils.kt
index 36dc148f..28d204cd 100644
--- a/decompose/src/jsMain/kotlin/com/arkivanov/decompose/router/stack/webhistory/Utils.kt
+++ b/decompose/src/jsMain/kotlin/com/arkivanov/decompose/router/stack/webhistory/Utils.kt
@@ -1,7 +1,6 @@
 package com.arkivanov.decompose.router.stack.webhistory
 
-import com.arkivanov.decompose.Child
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 
-internal fun <C : Any> RouterState<C, *>.configurations(): List<C> =
-    backStack.map(Child<C, *>::configuration) + active.configuration
+internal fun <C : Any> ChildStack<C, *>.configurations(): List<C> =
+    items.map { it.configuration }
diff --git a/extensions-android/src/main/java/com/arkivanov/decompose/extensions/android/stack/StackRouterView.kt b/extensions-android/src/main/java/com/arkivanov/decompose/extensions/android/stack/StackRouterView.kt
index fd3a7e47..c1353a18 100644
--- a/extensions-android/src/main/java/com/arkivanov/decompose/extensions/android/stack/StackRouterView.kt
+++ b/extensions-android/src/main/java/com/arkivanov/decompose/extensions/android/stack/StackRouterView.kt
@@ -16,7 +16,7 @@ import com.arkivanov.decompose.extensions.android.DefaultViewContext
 import com.arkivanov.decompose.extensions.android.ViewContext
 import com.arkivanov.decompose.extensions.android.forEachChild
 import com.arkivanov.decompose.lifecycle.MergedLifecycle
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 import com.arkivanov.decompose.value.Value
 import com.arkivanov.decompose.value.observe
 import com.arkivanov.essenty.lifecycle.Lifecycle
@@ -36,12 +36,12 @@ class StackRouterView @JvmOverloads constructor(
     private var savedState: Bundle? = null
 
     fun <C : Any, T : Any> children(
-        routerState: Value<RouterState<C, T>>,
+        stack: Value<ChildStack<C, T>>,
         lifecycle: Lifecycle,
         replaceChildView: ViewContext.(parent: ViewGroup, child: T, configuration: C) -> Unit
     ) {
-        routerState.observe(lifecycle) {
-            onStateChanged(it, lifecycle, replaceChildView)
+        stack.observe(lifecycle) {
+            onStackChanged(it, lifecycle, replaceChildView)
         }
     }
 
@@ -93,12 +93,12 @@ class StackRouterView @JvmOverloads constructor(
         }
 
     @OptIn(InternalDecomposeApi::class)
-    private fun <C : Any, T : Any> onStateChanged(
-        state: RouterState<C, T>,
+    private fun <C : Any, T : Any> onStackChanged(
+        stack: ChildStack<C, T>,
         lifecycle: Lifecycle,
         replaceChildView: ViewContext.(ViewGroup, T, C) -> Unit
     ) {
-        val activeChild = state.active
+        val activeChild = stack.active
         val currentChild: ActiveChild? = currentChild
 
         if (currentChild?.configuration === activeChild.configuration) {
@@ -107,7 +107,7 @@ class StackRouterView @JvmOverloads constructor(
 
         val currentChildView = currentChild?.let { findChildView(it.key) }
 
-        if ((currentChildView != null) && state.backStack.any { it.configuration === currentChild.configuration }) {
+        if ((currentChildView != null) && stack.backStack.any { it.configuration === currentChild.configuration }) {
             inactiveChildren[currentChild.key] = InactiveChild(currentChild.configuration, currentChildView.saveHierarchyState())
         }
         currentChild?.lifecycle?.destroy()
@@ -138,7 +138,7 @@ class StackRouterView @JvmOverloads constructor(
         this.currentChild = ActiveChild(activeChildKey, activeChild.configuration, childViewLifecycle)
 
         inactiveChildren.values.removeAll { child ->
-            state.backStack.none { it.configuration === child.configuration }
+            stack.backStack.none { it.configuration === child.configuration }
         }
     }
 
diff --git a/extensions-compose-jetbrains/api/android/extensions-compose-jetbrains.api b/extensions-compose-jetbrains/api/android/extensions-compose-jetbrains.api
index 63d861bb..03701207 100644
--- a/extensions-compose-jetbrains/api/android/extensions-compose-jetbrains.api
+++ b/extensions-compose-jetbrains/api/android/extensions-compose-jetbrains.api
@@ -76,7 +76,7 @@ public final class com/arkivanov/decompose/extensions/compose/jetbrains/animatio
 }
 
 public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/ChildrenKt {
-	public static final fun Children (Lcom/arkivanov/decompose/router/stack/RouterState;Landroidx/compose/ui/Modifier;Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V
+	public static final fun Children (Lcom/arkivanov/decompose/router/stack/ChildStack;Landroidx/compose/ui/Modifier;Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V
 	public static final fun Children (Lcom/arkivanov/decompose/value/Value;Landroidx/compose/ui/Modifier;Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V
 }
 
@@ -120,7 +120,7 @@ public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/an
 }
 
 public abstract interface class com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation {
-	public abstract fun invoke (Lcom/arkivanov/decompose/router/stack/RouterState;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;I)V
+	public abstract fun invoke (Lcom/arkivanov/decompose/router/stack/ChildStack;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;I)V
 }
 
 public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimationKt {
diff --git a/extensions-compose-jetbrains/api/jvm/extensions-compose-jetbrains.api b/extensions-compose-jetbrains/api/jvm/extensions-compose-jetbrains.api
index cb763d47..25bf0876 100644
--- a/extensions-compose-jetbrains/api/jvm/extensions-compose-jetbrains.api
+++ b/extensions-compose-jetbrains/api/jvm/extensions-compose-jetbrains.api
@@ -73,7 +73,7 @@ public final class com/arkivanov/decompose/extensions/compose/jetbrains/lifecycl
 }
 
 public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/ChildrenKt {
-	public static final fun Children (Lcom/arkivanov/decompose/router/stack/RouterState;Landroidx/compose/ui/Modifier;Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V
+	public static final fun Children (Lcom/arkivanov/decompose/router/stack/ChildStack;Landroidx/compose/ui/Modifier;Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V
 	public static final fun Children (Lcom/arkivanov/decompose/value/Value;Landroidx/compose/ui/Modifier;Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V
 }
 
@@ -117,7 +117,7 @@ public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/an
 }
 
 public abstract interface class com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation {
-	public abstract fun invoke (Lcom/arkivanov/decompose/router/stack/RouterState;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;I)V
+	public abstract fun invoke (Lcom/arkivanov/decompose/router/stack/ChildStack;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;I)V
 }
 
 public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimationKt {
diff --git a/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/Children.kt b/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/Children.kt
index 3ce711b2..7e2dcfe0 100644
--- a/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/Children.kt
+++ b/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/Children.kt
@@ -11,22 +11,22 @@ import com.arkivanov.decompose.ExperimentalDecomposeApi
 import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.StackAnimation
 import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.emptyStackAnimation
 import com.arkivanov.decompose.extensions.compose.jetbrains.subscribeAsState
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 import com.arkivanov.decompose.value.Value
 
 @OptIn(ExperimentalDecomposeApi::class)
 @Composable
 fun <C : Any, T : Any> Children(
-    routerState: RouterState<C, T>,
+    stack: ChildStack<C, T>,
     modifier: Modifier = Modifier,
     animation: StackAnimation<C, T> = emptyStackAnimation(),
     content: @Composable (child: Child.Created<C, T>) -> Unit,
 ) {
     val holder = rememberSaveableStateHolder()
 
-    holder.retainStates(routerState.getConfigurations())
+    holder.retainStates(stack.getConfigurations())
 
-    animation(state = routerState, modifier = modifier) { child ->
+    animation(stack = stack, modifier = modifier) { child ->
         holder.SaveableStateProvider(child.configuration.key()) {
             content(child)
         }
@@ -36,28 +36,23 @@ fun <C : Any, T : Any> Children(
 @OptIn(ExperimentalDecomposeApi::class)
 @Composable
 fun <C : Any, T : Any> Children(
-    routerState: Value<RouterState<C, T>>,
+    stack: Value<ChildStack<C, T>>,
     modifier: Modifier = Modifier,
     animation: StackAnimation<C, T> = emptyStackAnimation(),
     content: @Composable (child: Child.Created<C, T>) -> Unit,
 ) {
-    val state = routerState.subscribeAsState()
+    val state = stack.subscribeAsState()
 
     Children(
-        routerState = state.value,
+        stack = state.value,
         modifier = modifier,
         animation = animation,
         content = content
     )
 }
 
-private fun RouterState<*, *>.getConfigurations(): Set<String> {
-    val set = HashSet<String>()
-    backStack.forEach { set += it.configuration.key() }
-    set += active.configuration.key()
-
-    return set
-}
+private fun ChildStack<*, *>.getConfigurations(): Set<String> =
+    items.mapTo(HashSet()) { it.configuration.key() }
 
 private fun Any.key(): String = "${this::class.simpleName}_${hashCode().toString(radix = 36)}"
 
diff --git a/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/DefaultStackAnimation.kt b/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/DefaultStackAnimation.kt
index 71792e5f..81c10937 100644
--- a/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/DefaultStackAnimation.kt
+++ b/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/DefaultStackAnimation.kt
@@ -14,7 +14,7 @@ import androidx.compose.ui.input.pointer.consumeAllChanges
 import androidx.compose.ui.input.pointer.pointerInput
 import com.arkivanov.decompose.Child
 import com.arkivanov.decompose.ExperimentalDecomposeApi
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 
 @ExperimentalDecomposeApi
 internal class DefaultStackAnimation<C : Any, T : Any>(
@@ -22,13 +22,13 @@ internal class DefaultStackAnimation<C : Any, T : Any>(
 ) : StackAnimation<C, T> {
 
     @Composable
-    override operator fun invoke(state: RouterState<C, T>, modifier: Modifier, content: @Composable (child: Child.Created<C, T>) -> Unit) {
-        var activePage by remember { mutableStateOf(state.activePage()) }
+    override operator fun invoke(stack: ChildStack<C, T>, modifier: Modifier, content: @Composable (child: Child.Created<C, T>) -> Unit) {
+        var activePage by remember { mutableStateOf(stack.activePage()) }
         var items by remember { mutableStateOf(getAnimationItems(newPage = activePage, oldPage = null)) }
 
-        if (state.active.configuration != activePage.child.configuration) {
+        if (stack.active.configuration != activePage.child.configuration) {
             val oldPage = activePage
-            activePage = state.activePage()
+            activePage = stack.activePage()
             items = getAnimationItems(newPage = activePage, oldPage = oldPage)
         }
 
@@ -80,8 +80,8 @@ internal class DefaultStackAnimation<C : Any, T : Any>(
         )
     }
 
-    private fun RouterState<C, T>.activePage(): Page<C, T> =
-        Page(child = active, index = backStack.size)
+    private fun ChildStack<C, T>.activePage(): Page<C, T> =
+        Page(child = active, index = items.lastIndex)
 
     private fun getAnimationItems(newPage: Page<C, T>, oldPage: Page<C, T>?): Map<C, AnimationItem<C, T>> =
         when {
diff --git a/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/EmptyStackAnimation.kt b/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/EmptyStackAnimation.kt
index 5f671d6a..dbb589f8 100644
--- a/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/EmptyStackAnimation.kt
+++ b/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/EmptyStackAnimation.kt
@@ -5,8 +5,8 @@ import com.arkivanov.decompose.ExperimentalDecomposeApi
 
 @ExperimentalDecomposeApi
 internal fun <C : Any, T : Any> emptyStackAnimation(): StackAnimation<C, T> =
-    StackAnimation { routerState, modifier, childContent ->
+    StackAnimation { stack, modifier, childContent ->
         Box(modifier = modifier) {
-            childContent(routerState.active)
+            childContent(stack.active)
         }
     }
diff --git a/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation.kt b/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation.kt
index 8cbaf0a2..6d4bc8b7 100644
--- a/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation.kt
+++ b/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation.kt
@@ -6,17 +6,17 @@ import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import com.arkivanov.decompose.Child
 import com.arkivanov.decompose.ExperimentalDecomposeApi
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 
 /**
- * Tracks the [RouterState] changes and animates between child widget.
+ * Tracks the [ChildStack] changes and animates between child widget.
  */
 @ExperimentalDecomposeApi
 interface StackAnimation<C : Any, T : Any> {
 
     @Composable
     operator fun invoke(
-        state: RouterState<C, T>,
+        stack: ChildStack<C, T>,
         modifier: Modifier,
         content: @Composable (child: Child.Created<C, T>) -> Unit,
     )
@@ -30,7 +30,7 @@ interface StackAnimation<C : Any, T : Any> {
 @ExperimentalDecomposeApi
 inline fun <C : Any, T : Any> StackAnimation(
     crossinline content: @Composable (
-        state: RouterState<C, T>,
+        stack: ChildStack<C, T>,
         modifier: Modifier,
         content: @Composable (child: Child.Created<C, T>) -> Unit,
     ) -> Unit
@@ -38,11 +38,11 @@ inline fun <C : Any, T : Any> StackAnimation(
     object : StackAnimation<C, T> {
         @Composable
         override operator fun invoke(
-            state: RouterState<C, T>,
+            stack: ChildStack<C, T>,
             modifier: Modifier,
             content: @Composable (child: Child.Created<C, T>) -> Unit,
         ) {
-            content(state, modifier, content)
+            content(stack, modifier, content)
         }
     }
 
diff --git a/extensions-compose-jetpack/api/extensions-compose-jetpack.api b/extensions-compose-jetpack/api/extensions-compose-jetpack.api
index 6cc91e49..aa01ca21 100644
--- a/extensions-compose-jetpack/api/extensions-compose-jetpack.api
+++ b/extensions-compose-jetpack/api/extensions-compose-jetpack.api
@@ -76,7 +76,7 @@ public final class com/arkivanov/decompose/extensions/compose/jetpack/animation/
 }
 
 public final class com/arkivanov/decompose/extensions/compose/jetpack/stack/ChildrenKt {
-	public static final fun Children (Lcom/arkivanov/decompose/router/stack/RouterState;Landroidx/compose/ui/Modifier;Lcom/arkivanov/decompose/extensions/compose/jetpack/stack/animation/StackAnimation;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V
+	public static final fun Children (Lcom/arkivanov/decompose/router/stack/ChildStack;Landroidx/compose/ui/Modifier;Lcom/arkivanov/decompose/extensions/compose/jetpack/stack/animation/StackAnimation;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V
 	public static final fun Children (Lcom/arkivanov/decompose/value/Value;Landroidx/compose/ui/Modifier;Lcom/arkivanov/decompose/extensions/compose/jetpack/stack/animation/StackAnimation;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V
 }
 
@@ -120,7 +120,7 @@ public final class com/arkivanov/decompose/extensions/compose/jetpack/stack/anim
 }
 
 public abstract interface class com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/StackAnimation {
-	public abstract fun invoke (Lcom/arkivanov/decompose/router/stack/RouterState;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;I)V
+	public abstract fun invoke (Lcom/arkivanov/decompose/router/stack/ChildStack;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;I)V
 }
 
 public final class com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/StackAnimationKt {
diff --git a/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/Children.kt b/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/Children.kt
index 7d2af926..d3033799 100644
--- a/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/Children.kt
+++ b/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/Children.kt
@@ -12,22 +12,22 @@ import com.arkivanov.decompose.ExperimentalDecomposeApi
 import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.StackAnimation
 import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.emptyStackAnimation
 import com.arkivanov.decompose.extensions.compose.jetpack.subscribeAsState
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 import com.arkivanov.decompose.value.Value
 
 @OptIn(ExperimentalDecomposeApi::class)
 @Composable
 fun <C : Any, T : Any> Children(
-    routerState: RouterState<C, T>,
+    stack: ChildStack<C, T>,
     modifier: Modifier = Modifier,
     animation: StackAnimation<C, T> = emptyStackAnimation(),
     content: @Composable (child: Child.Created<C, T>) -> Unit,
 ) {
     val holder = rememberSaveableStateHolder()
 
-    holder.retainStates(routerState.getConfigurations())
+    holder.retainStates(stack.getConfigurations())
 
-    animation(state = routerState, modifier = modifier) { child ->
+    animation(stack = stack, modifier = modifier) { child ->
         holder.SaveableStateProvider(child.configuration.key()) {
             content(child)
         }
@@ -37,28 +37,23 @@ fun <C : Any, T : Any> Children(
 @OptIn(ExperimentalDecomposeApi::class)
 @Composable
 fun <C : Any, T : Any> Children(
-    routerState: Value<RouterState<C, T>>,
+    stack: Value<ChildStack<C, T>>,
     modifier: Modifier = Modifier,
     animation: StackAnimation<C, T> = emptyStackAnimation(),
     content: @Composable (child: Child.Created<C, T>) -> Unit,
 ) {
-    val state = routerState.subscribeAsState()
+    val state = stack.subscribeAsState()
 
     Children(
-        routerState = state.value,
+        stack = state.value,
         modifier = modifier,
         animation = animation,
         content = content
     )
 }
 
-private fun RouterState<*, *>.getConfigurations(): Set<String> {
-    val set = HashSet<String>()
-    backStack.forEach { set += it.configuration.key() }
-    set += active.configuration.key()
-
-    return set
-}
+private fun ChildStack<*, *>.getConfigurations(): Set<String> =
+    items.mapTo(HashSet()) { it.configuration.key() }
 
 private fun Any.key(): String = "${this::class.simpleName}_${hashCode().toString(radix = 36)}"
 
diff --git a/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/DefaultStackAnimation.kt b/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/DefaultStackAnimation.kt
index 498766f6..c281e43e 100644
--- a/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/DefaultStackAnimation.kt
+++ b/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/DefaultStackAnimation.kt
@@ -14,7 +14,7 @@ import androidx.compose.ui.input.pointer.consumeAllChanges
 import androidx.compose.ui.input.pointer.pointerInput
 import com.arkivanov.decompose.Child
 import com.arkivanov.decompose.ExperimentalDecomposeApi
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 
 @ExperimentalDecomposeApi
 internal class DefaultStackAnimation<C : Any, T : Any>(
@@ -22,13 +22,13 @@ internal class DefaultStackAnimation<C : Any, T : Any>(
 ) : StackAnimation<C, T> {
 
     @Composable
-    override operator fun invoke(state: RouterState<C, T>, modifier: Modifier, content: @Composable (child: Child.Created<C, T>) -> Unit) {
-        var activePage by remember { mutableStateOf(state.activePage()) }
+    override operator fun invoke(stack: ChildStack<C, T>, modifier: Modifier, content: @Composable (child: Child.Created<C, T>) -> Unit) {
+        var activePage by remember { mutableStateOf(stack.activePage()) }
         var items by remember { mutableStateOf(getAnimationItems(newPage = activePage, oldPage = null)) }
 
-        if (state.active.configuration != activePage.child.configuration) {
+        if (stack.active.configuration != activePage.child.configuration) {
             val oldPage = activePage
-            activePage = state.activePage()
+            activePage = stack.activePage()
             items = getAnimationItems(newPage = activePage, oldPage = oldPage)
         }
 
@@ -80,8 +80,8 @@ internal class DefaultStackAnimation<C : Any, T : Any>(
         )
     }
 
-    private fun RouterState<C, T>.activePage(): Page<C, T> =
-        Page(child = active, index = backStack.size)
+    private fun ChildStack<C, T>.activePage(): Page<C, T> =
+        Page(child = active, index = items.lastIndex)
 
     private fun getAnimationItems(newPage: Page<C, T>, oldPage: Page<C, T>?): Map<C, AnimationItem<C, T>> =
         when {
diff --git a/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/EmptyStackAnimation.kt b/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/EmptyStackAnimation.kt
index 3421fef1..3c3ac946 100644
--- a/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/EmptyStackAnimation.kt
+++ b/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/EmptyStackAnimation.kt
@@ -5,8 +5,8 @@ import com.arkivanov.decompose.ExperimentalDecomposeApi
 
 @ExperimentalDecomposeApi
 internal fun <C : Any, T : Any> emptyStackAnimation(): StackAnimation<C, T> =
-    StackAnimation { routerState, modifier, childContent ->
+    StackAnimation { stack, modifier, childContent ->
         Box(modifier = modifier) {
-            childContent(routerState.active)
+            childContent(stack.active)
         }
     }
diff --git a/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/StackAnimation.kt b/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/StackAnimation.kt
index f69b42b1..392c6949 100644
--- a/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/StackAnimation.kt
+++ b/extensions-compose-jetpack/src/main/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/animation/StackAnimation.kt
@@ -6,17 +6,17 @@ import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import com.arkivanov.decompose.Child
 import com.arkivanov.decompose.ExperimentalDecomposeApi
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 
 /**
- * Tracks the [RouterState] changes and animates between child widget.
+ * Tracks the [ChildStack] changes and animates between child widget.
  */
 @ExperimentalDecomposeApi
 interface StackAnimation<C : Any, T : Any> {
 
     @Composable
     operator fun invoke(
-        state: RouterState<C, T>,
+        stack: ChildStack<C, T>,
         modifier: Modifier,
         content: @Composable (child: Child.Created<C, T>) -> Unit,
     )
@@ -30,7 +30,7 @@ interface StackAnimation<C : Any, T : Any> {
 @ExperimentalDecomposeApi
 inline fun <C : Any, T : Any> StackAnimation(
     crossinline content: @Composable (
-        state: RouterState<C, T>,
+        stack: ChildStack<C, T>,
         modifier: Modifier,
         content: @Composable (child: Child.Created<C, T>) -> Unit,
     ) -> Unit
@@ -38,11 +38,11 @@ inline fun <C : Any, T : Any> StackAnimation(
     object : StackAnimation<C, T> {
         @Composable
         override operator fun invoke(
-            state: RouterState<C, T>,
+            stack: ChildStack<C, T>,
             modifier: Modifier,
             content: @Composable (child: Child.Created<C, T>) -> Unit,
         ) {
-            content(state, modifier, content)
+            content(stack, modifier, content)
         }
     }
 
diff --git a/sample/app-ios/app-ios.xcodeproj/project.pbxproj b/sample/app-ios/app-ios.xcodeproj/project.pbxproj
index f1a47143..4aa978d8 100644
--- a/sample/app-ios/app-ios.xcodeproj/project.pbxproj
+++ b/sample/app-ios/app-ios.xcodeproj/project.pbxproj
@@ -14,7 +14,7 @@
 		798DB84A282F08670072CCBD /* CounterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 798DB849282F08670072CCBD /* CounterView.swift */; };
 		798DB84C282F088C0072CCBD /* ObservableValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 798DB84B282F088C0072CCBD /* ObservableValue.swift */; };
 		798DB84E282F08E00072CCBD /* MutableValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 798DB84D282F08E00072CCBD /* MutableValue.swift */; };
-		798DB850282F08FC0072CCBD /* SimpleRouterState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 798DB84F282F08FC0072CCBD /* SimpleRouterState.swift */; };
+		798DB850282F08FC0072CCBD /* SimpleChildStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 798DB84F282F08FC0072CCBD /* SimpleChildStack.swift */; };
 		798DB852282F096C0072CCBD /* CountersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 798DB851282F096C0072CCBD /* CountersView.swift */; };
 		798DB854282F09FE0072CCBD /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 798DB853282F09FE0072CCBD /* RootView.swift */; };
 		798DB856282F0E6F0072CCBD /* MultiPaneView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 798DB855282F0E6F0072CCBD /* MultiPaneView.swift */; };
@@ -31,7 +31,7 @@
 		798DB849282F08670072CCBD /* CounterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CounterView.swift; sourceTree = "<group>"; };
 		798DB84B282F088C0072CCBD /* ObservableValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObservableValue.swift; sourceTree = "<group>"; };
 		798DB84D282F08E00072CCBD /* MutableValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MutableValue.swift; sourceTree = "<group>"; };
-		798DB84F282F08FC0072CCBD /* SimpleRouterState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleRouterState.swift; sourceTree = "<group>"; };
+		798DB84F282F08FC0072CCBD /* SimpleChildStack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleChildStack.swift; sourceTree = "<group>"; };
 		798DB851282F096C0072CCBD /* CountersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CountersView.swift; sourceTree = "<group>"; };
 		798DB853282F09FE0072CCBD /* RootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootView.swift; sourceTree = "<group>"; };
 		798DB855282F0E6F0072CCBD /* MultiPaneView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiPaneView.swift; sourceTree = "<group>"; };
@@ -76,7 +76,7 @@
 				798DB849282F08670072CCBD /* CounterView.swift */,
 				798DB84B282F088C0072CCBD /* ObservableValue.swift */,
 				798DB84D282F08E00072CCBD /* MutableValue.swift */,
-				798DB84F282F08FC0072CCBD /* SimpleRouterState.swift */,
+				798DB84F282F08FC0072CCBD /* SimpleChildStack.swift */,
 				798DB851282F096C0072CCBD /* CountersView.swift */,
 				798DB853282F09FE0072CCBD /* RootView.swift */,
 				798DB855282F0E6F0072CCBD /* MultiPaneView.swift */,
@@ -192,7 +192,7 @@
 				798DB84E282F08E00072CCBD /* MutableValue.swift in Sources */,
 				798DB856282F0E6F0072CCBD /* MultiPaneView.swift in Sources */,
 				798DB84C282F088C0072CCBD /* ObservableValue.swift in Sources */,
-				798DB850282F08FC0072CCBD /* SimpleRouterState.swift in Sources */,
+				798DB850282F08FC0072CCBD /* SimpleChildStack.swift in Sources */,
 				798DB852282F096C0072CCBD /* CountersView.swift in Sources */,
 				798DB85A282F11800072CCBD /* ArticleDetailsView.swift in Sources */,
 				798DB84A282F08670072CCBD /* CounterView.swift in Sources */,
diff --git a/sample/app-ios/app-ios/CountersView.swift b/sample/app-ios/app-ios/CountersView.swift
index a6dd0e04..40cbd0e7 100644
--- a/sample/app-ios/app-ios/CountersView.swift
+++ b/sample/app-ios/app-ios/CountersView.swift
@@ -12,24 +12,24 @@ struct CountersView: View {
     private let counters: Counters
 
     @ObservedObject
-    private var firstRouterState: ObservableValue<RouterState<AnyObject, Counter>>
+    private var firstChildStack: ObservableValue<ChildStack<AnyObject, Counter>>
 
     @ObservedObject
-    private var secondRouterState: ObservableValue<RouterState<AnyObject, Counter>>
+    private var secondChildStack: ObservableValue<ChildStack<AnyObject, Counter>>
 
-    private var firstActiveChild: Counter { firstRouterState.value.activeChild.instance }
-    private var secondActiveChild: Counter { secondRouterState.value.activeChild.instance }
+    private var firstActiveChild: Counter { firstChildStack.value.active.instance }
+    private var secondActiveChild: Counter { secondChildStack.value.active.instance }
 
     init(_ counters: Counters) {
         self.counters = counters
-        firstRouterState = ObservableValue(counters.firstRouterState)
-        secondRouterState = ObservableValue(counters.secondRouterState)
+        firstChildStack = ObservableValue(counters.firstChildStack)
+        secondChildStack = ObservableValue(counters.secondChildStack)
     }
 
     var body: some View {
         VStack(spacing: 8) {
-            CounterView(firstRouterState.value.activeChild.instance)
-            CounterView(secondRouterState.value.activeChild.instance)
+            CounterView(firstChildStack.value.active.instance)
+            CounterView(secondChildStack.value.active.instance)
         }
     }
 }
@@ -41,6 +41,6 @@ struct CountersView_Previews: PreviewProvider {
 }
 
 class CountersPreview : Counters {
-    let firstRouterState: Value<RouterState<AnyObject, Counter>> = simpleRouterState(CounterPreview())
-    let secondRouterState: Value<RouterState<AnyObject, Counter>> = simpleRouterState(CounterPreview())
+    let firstChildStack: Value<ChildStack<AnyObject, Counter>> = simpleChildStack(CounterPreview())
+    let secondChildStack: Value<ChildStack<AnyObject, Counter>> = simpleChildStack(CounterPreview())
 }
diff --git a/sample/app-ios/app-ios/MultiPaneView.swift b/sample/app-ios/app-ios/MultiPaneView.swift
index d1a416b9..b64854b5 100644
--- a/sample/app-ios/app-ios/MultiPaneView.swift
+++ b/sample/app-ios/app-ios/MultiPaneView.swift
@@ -18,20 +18,20 @@ struct MultiPaneView: View {
     private var observableModel: ObservableValue<MultiPaneModel>
     
     @ObservedObject
-    private var listRouterState: ObservableValue<RouterState<AnyObject, MultiPaneListChild>>
+    private var listChildStack: ObservableValue<ChildStack<AnyObject, MultiPaneListChild>>
     
     @ObservedObject
-    private var detailsRouterState: ObservableValue<RouterState<AnyObject, MultiPaneDetailsChild>>
+    private var detailsChildStack: ObservableValue<ChildStack<AnyObject, MultiPaneDetailsChild>>
     
     private var model: MultiPaneModel { observableModel.value }
-    private var activeListChild: MultiPaneListChild { listRouterState.value.activeChild.instance }
-    private var activeDetailsChild: MultiPaneDetailsChild { detailsRouterState.value.activeChild.instance }
+    private var activeListChild: MultiPaneListChild { listChildStack.value.active.instance }
+    private var activeDetailsChild: MultiPaneDetailsChild { detailsChildStack.value.active.instance }
     
     init(_ component: MultiPane) {
         self.component = component
         observableModel = ObservableValue(component.models)
-        listRouterState = ObservableValue(component.listRouterState)
-        detailsRouterState = ObservableValue(component.detailsRouterState)
+        listChildStack = ObservableValue(component.listChildStack)
+        detailsChildStack = ObservableValue(component.detailsChildStack)
     }
     
     var body: some View {
@@ -99,11 +99,11 @@ struct MultiPaneView_Previews: PreviewProvider {
 }
 
 class MultiPanePreview: MultiPane {
-    var listRouterState: Value<RouterState<AnyObject, MultiPaneListChild>> =
-        simpleRouterState(.List(component: ArticleListPreview()))
+    var listChildStack: Value<ChildStack<AnyObject, MultiPaneListChild>> =
+        simpleChildStack(.List(component: ArticleListPreview()))
 
-    var detailsRouterState: Value<RouterState<AnyObject, MultiPaneDetailsChild>> =
-        simpleRouterState(.Details(component: ArticleDetailsPreview()))
+    var detailsChildStack: Value<ChildStack<AnyObject, MultiPaneDetailsChild>> =
+        simpleChildStack(.Details(component: ArticleDetailsPreview()))
 
     var models: Value<MultiPaneModel> = mutableValue(MultiPaneModel(isMultiPane: true))
 
diff --git a/sample/app-ios/app-ios/RootView.swift b/sample/app-ios/app-ios/RootView.swift
index 5f6b311c..ee5897a2 100644
--- a/sample/app-ios/app-ios/RootView.swift
+++ b/sample/app-ios/app-ios/RootView.swift
@@ -12,13 +12,13 @@ struct RootView: View {
     private let root: Root
     
     @ObservedObject
-    private var routerState: ObservableValue<RouterState<AnyObject, RootChild>>
+    private var childStack: ObservableValue<ChildStack<AnyObject, RootChild>>
     
-    private var activeChild: RootChild { routerState.value.activeChild.instance }
+    private var activeChild: RootChild { childStack.value.active.instance }
     
     init(_ root: Root) {
         self.root = root
-        routerState = ObservableValue(root.routerState)
+        childStack = ObservableValue(root.childStack)
     }
     
     var body: some View {
@@ -71,8 +71,8 @@ struct RootView_Previews: PreviewProvider {
 }
 
 class RootPreview : Root {
-    let routerState: Value<RouterState<AnyObject, RootChild>> =
-        simpleRouterState(RootChild.CountersChild(component: CountersPreview()))
+    let childStack: Value<ChildStack<AnyObject, RootChild>> =
+        simpleChildStack(RootChild.CountersChild(component: CountersPreview()))
 
     func onCountersTabClicked() {}
     func onMultiPaneTabClicked() {}
diff --git a/sample/app-ios/app-ios/SimpleRouterState.swift b/sample/app-ios/app-ios/SimpleChildStack.swift
similarity index 67%
rename from sample/app-ios/app-ios/SimpleRouterState.swift
rename to sample/app-ios/app-ios/SimpleChildStack.swift
index b063c371..0ab1eba0 100644
--- a/sample/app-ios/app-ios/SimpleRouterState.swift
+++ b/sample/app-ios/app-ios/SimpleChildStack.swift
@@ -7,9 +7,9 @@
 
 import Shared
 
-func simpleRouterState<T : AnyObject>(_ child: T) -> Value<RouterState<AnyObject, T>> {
+func simpleChildStack<T : AnyObject>(_ child: T) -> Value<ChildStack<AnyObject, T>> {
     return mutableValue(
-        RouterState(
+        ChildStack(
             configuration: "config" as AnyObject,
             instance: child
         )
diff --git a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/counters/CountersContent.kt b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/counters/CountersContent.kt
index 26678ff7..bfb5e49d 100644
--- a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/counters/CountersContent.kt
+++ b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/counters/CountersContent.kt
@@ -9,7 +9,7 @@ import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import com.arkivanov.decompose.ExperimentalDecomposeApi
 import com.arkivanov.decompose.extensions.compose.jetbrains.stack.Children
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 import com.arkivanov.decompose.value.MutableValue
 import com.arkivanov.decompose.value.Value
 import com.arkivanov.sample.shared.counters.counter.Counter
@@ -22,11 +22,11 @@ import com.arkivanov.sample.shared.utils.orientation
 @Composable
 internal fun CountersContent(component: Counters, modifier: Modifier = Modifier) {
     ColumnOrRow(modifier = modifier) {
-        Children(routerState = component.firstRouterState) {
+        Children(stack = component.firstChildStack) {
             CounterContent(component = it.instance)
         }
 
-        Children(routerState = component.secondRouterState) {
+        Children(stack = component.secondChildStack) {
             CounterContent(component = it.instance)
         }
     }
@@ -58,17 +58,17 @@ internal fun TabContentPreview() {
 }
 
 internal class CountersPreview : Counters {
-    override val firstRouterState: Value<RouterState<*, Counter>> =
+    override val firstChildStack: Value<ChildStack<*, Counter>> =
         MutableValue(
-            RouterState(
+            ChildStack(
                 configuration = Unit,
                 instance = CounterPreview(),
             )
         )
 
-    override val secondRouterState: Value<RouterState<*, Counter>> =
+    override val secondChildStack: Value<ChildStack<*, Counter>> =
         MutableValue(
-            RouterState(
+            ChildStack(
                 configuration = Unit,
                 instance = CounterPreview(),
             )
diff --git a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/DynamicFeaturesContent.kt b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/DynamicFeaturesContent.kt
index 38b79d61..31c733f4 100644
--- a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/DynamicFeaturesContent.kt
+++ b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/DynamicFeaturesContent.kt
@@ -17,7 +17,7 @@ import com.arkivanov.sample.shared.dynamicfeatures.feature2.feature2Content
 @Composable
 internal fun DynamicFeaturesContent(component: DynamicFeatures, modifier: Modifier = Modifier) {
     Children(
-        routerState = component.routerState,
+        stack = component.childStack,
         modifier = modifier,
         animation = stackAnimation(fade()),
     ) {
diff --git a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/dynamicfeature/DynamicFeatureContent.kt b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/dynamicfeature/DynamicFeatureContent.kt
index fc024dd1..c5c23ead 100644
--- a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/dynamicfeature/DynamicFeatureContent.kt
+++ b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/dynamicfeature/DynamicFeatureContent.kt
@@ -21,7 +21,7 @@ fun <T : Any> DynamicFeatureContent(
     contentSupplier: () -> DynamicFeatureContent<T>,
 ) {
     Children(
-        routerState = dynamicFeature.routerState,
+        stack = dynamicFeature.childStack,
         modifier = modifier,
         animation = stackAnimation(fade()),
     ) {
diff --git a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/multipane/MultiPaneContent.kt b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/multipane/MultiPaneContent.kt
index 67d66f0c..2db17253 100644
--- a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/multipane/MultiPaneContent.kt
+++ b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/multipane/MultiPaneContent.kt
@@ -14,7 +14,7 @@ import com.arkivanov.decompose.extensions.compose.jetbrains.stack.Children
 import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.fade
 import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.stackAnimation
 import com.arkivanov.decompose.extensions.compose.jetbrains.subscribeAsState
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 import com.arkivanov.decompose.value.Value
 import com.arkivanov.sample.shared.multipane.MultiPane.DetailsChild
 import com.arkivanov.sample.shared.multipane.MultiPane.ListChild
@@ -33,7 +33,7 @@ internal fun MultiPaneContent(component: MultiPane, modifier: Modifier = Modifie
 
         Row(modifier = Modifier.fillMaxSize()) {
             ListPane(
-                routerState = component.listRouterState,
+                stack = component.listChildStack,
                 modifier = Modifier.weight(if (isMultiPane) LIST_PANE_WEIGHT else 1F),
             )
 
@@ -48,7 +48,7 @@ internal fun MultiPaneContent(component: MultiPane, modifier: Modifier = Modifie
             }
 
             DetailsPane(
-                routerState = component.detailsRouterState,
+                stack = component.detailsChildStack,
                 modifier = Modifier.weight(if (isMultiPane) DETAILS_PANE_WEIGHT else 1F),
             )
         }
@@ -64,9 +64,9 @@ internal fun MultiPaneContent(component: MultiPane, modifier: Modifier = Modifie
 
 @OptIn(ExperimentalDecomposeApi::class)
 @Composable
-private fun ListPane(routerState: Value<RouterState<*, ListChild>>, modifier: Modifier) {
+private fun ListPane(stack: Value<ChildStack<*, ListChild>>, modifier: Modifier) {
     Children(
-        routerState = routerState,
+        stack = stack,
         modifier = modifier,
         animation = stackAnimation(fade()),
     ) {
@@ -79,9 +79,9 @@ private fun ListPane(routerState: Value<RouterState<*, ListChild>>, modifier: Mo
 
 @OptIn(ExperimentalDecomposeApi::class)
 @Composable
-private fun DetailsPane(routerState: Value<RouterState<*, DetailsChild>>, modifier: Modifier) {
+private fun DetailsPane(stack: Value<ChildStack<*, DetailsChild>>, modifier: Modifier) {
     Children(
-        routerState = routerState,
+        stack = stack,
         modifier = modifier,
         animation = stackAnimation(fade()),
     ) {
diff --git a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/root/RootContent.kt b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/root/RootContent.kt
index 68bf823b..4c57e3af 100644
--- a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/root/RootContent.kt
+++ b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/root/RootContent.kt
@@ -18,7 +18,7 @@ import androidx.compose.ui.Modifier
 import com.arkivanov.decompose.ExperimentalDecomposeApi
 import com.arkivanov.decompose.extensions.compose.jetbrains.stack.Children
 import com.arkivanov.decompose.extensions.compose.jetbrains.subscribeAsState
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 import com.arkivanov.decompose.value.MutableValue
 import com.arkivanov.decompose.value.Value
 import com.arkivanov.sample.shared.counters.CountersContent
@@ -32,12 +32,12 @@ import com.arkivanov.sample.shared.root.Root.Child.MultiPaneChild
 @OptIn(ExperimentalDecomposeApi::class)
 @Composable
 fun RootContent(root: Root, modifier: Modifier = Modifier) {
-    val routerState by root.routerState.subscribeAsState()
-    val activeComponent = routerState.active.instance
+    val childStack by root.childStack.subscribeAsState()
+    val activeComponent = childStack.active.instance
 
     Column(modifier = modifier) {
         Children(
-            routerState = routerState,
+            stack = childStack,
             modifier = Modifier.weight(weight = 1F),
         ) {
             when (val child = it.instance) {
@@ -94,9 +94,9 @@ internal fun RootContentPreview() {
 }
 
 internal class RootPreview : Root {
-    override val routerState: Value<RouterState<*, Root.Child>> =
+    override val childStack: Value<ChildStack<*, Root.Child>> =
         MutableValue(
-            RouterState(
+            ChildStack(
                 configuration = Unit,
                 instance = CountersChild(component = CountersPreview()),
             )
diff --git a/sample/shared/shared/src/androidMain/kotlin/com/arkivanov/sample/shared/counters/CountersView.kt b/sample/shared/shared/src/androidMain/kotlin/com/arkivanov/sample/shared/counters/CountersView.kt
index 8ecf6914..55796f87 100644
--- a/sample/shared/shared/src/androidMain/kotlin/com/arkivanov/sample/shared/counters/CountersView.kt
+++ b/sample/shared/shared/src/androidMain/kotlin/com/arkivanov/sample/shared/counters/CountersView.kt
@@ -25,12 +25,12 @@ internal fun ViewContext.CountersView(counters: Counters): View {
             LinearLayout.VERTICAL
         }
 
-    firstRouter.children(counters.firstRouterState, lifecycle) { parent, child, _ ->
+    firstRouter.children(counters.firstChildStack, lifecycle) { parent, child, _ ->
         parent.removeAllViews()
         parent.addView(CounterView(child))
     }
 
-    secondRouter.children(counters.secondRouterState, lifecycle) { parent, child, _ ->
+    secondRouter.children(counters.secondChildStack, lifecycle) { parent, child, _ ->
         parent.removeAllViews()
         parent.addView(CounterView(child))
     }
diff --git a/sample/shared/shared/src/androidMain/kotlin/com/arkivanov/sample/shared/root/RootView.kt b/sample/shared/shared/src/androidMain/kotlin/com/arkivanov/sample/shared/root/RootView.kt
index dfa2f9a6..b089ac9c 100644
--- a/sample/shared/shared/src/androidMain/kotlin/com/arkivanov/sample/shared/root/RootView.kt
+++ b/sample/shared/shared/src/androidMain/kotlin/com/arkivanov/sample/shared/root/RootView.kt
@@ -19,7 +19,7 @@ fun ViewContext.RootView(root: Root): View {
     val layout = layoutInflater.inflate(R.layout.root, parent, false)
     val router: StackRouterView = layout.findViewById(R.id.router)
 
-    router.children(root.routerState, lifecycle) { parent, child, _ ->
+    router.children(root.childStack, lifecycle) { parent, child, _ ->
         parent.removeAllViews()
 
         parent.addView(
@@ -47,7 +47,7 @@ fun ViewContext.RootView(root: Root): View {
 
     navigationView.setOnNavigationItemSelectedListener(listener)
 
-    root.routerState.observe(lifecycle) { state ->
+    root.childStack.observe(lifecycle) { state ->
         navigationView.setOnNavigationItemSelectedListener(null)
 
         navigationView.selectedItemId =
diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/counters/Counters.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/counters/Counters.kt
index c9f0f940..3296f645 100644
--- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/counters/Counters.kt
+++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/counters/Counters.kt
@@ -1,11 +1,11 @@
 package com.arkivanov.sample.shared.counters
 
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 import com.arkivanov.decompose.value.Value
 import com.arkivanov.sample.shared.counters.counter.Counter
 
 interface Counters {
 
-    val firstRouterState: Value<RouterState<*, Counter>>
-    val secondRouterState: Value<RouterState<*, Counter>>
+    val firstChildStack: Value<ChildStack<*, Counter>>
+    val secondChildStack: Value<ChildStack<*, Counter>>
 }
diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/counters/CountersComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/counters/CountersComponent.kt
index 4f4b847a..3eaddf9b 100644
--- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/counters/CountersComponent.kt
+++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/counters/CountersComponent.kt
@@ -1,7 +1,7 @@
 package com.arkivanov.sample.shared.counters
 
 import com.arkivanov.decompose.ComponentContext
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 import com.arkivanov.decompose.router.stack.StackRouter
 import com.arkivanov.decompose.router.stack.pop
 import com.arkivanov.decompose.router.stack.push
@@ -23,7 +23,7 @@ internal class CountersComponent(
             childFactory = ::firstChild,
         )
 
-    override val firstRouterState: Value<RouterState<*, Counter>> get() = firstRouter.state
+    override val firstChildStack: Value<ChildStack<*, Counter>> get() = firstRouter.stack
 
     private val secondRouter: StackRouter<Config, Counter> =
         stackRouter(
@@ -32,7 +32,7 @@ internal class CountersComponent(
             childFactory = ::secondChild,
         )
 
-    override val secondRouterState: Value<RouterState<*, Counter>> get() = secondRouter.state
+    override val secondChildStack: Value<ChildStack<*, Counter>> get() = secondRouter.stack
 
     private fun firstChild(
         config: Config,
diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/DynamicFeatures.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/DynamicFeatures.kt
index 34ed4eb6..65ecdf85 100644
--- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/DynamicFeatures.kt
+++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/DynamicFeatures.kt
@@ -1,6 +1,6 @@
 package com.arkivanov.sample.shared.dynamicfeatures
 
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 import com.arkivanov.decompose.value.Value
 import com.arkivanov.sample.shared.dynamicfeatures.dynamicfeature.DynamicFeature
 import com.arkivanov.sample.shared.dynamicfeatures.feature1.Feature1
@@ -8,7 +8,7 @@ import com.arkivanov.sample.shared.dynamicfeatures.feature2.Feature2
 
 interface DynamicFeatures {
 
-    val routerState: Value<RouterState<*, Child>>
+    val childStack: Value<ChildStack<*, Child>>
 
     sealed class Child {
         class Feature1Child(val feature1: DynamicFeature<Feature1>) : Child()
diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/DynamicFeaturesComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/DynamicFeaturesComponent.kt
index 188b5a5c..834f5386 100644
--- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/DynamicFeaturesComponent.kt
+++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/DynamicFeaturesComponent.kt
@@ -1,7 +1,7 @@
 package com.arkivanov.sample.shared.dynamicfeatures
 
 import com.arkivanov.decompose.ComponentContext
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 import com.arkivanov.decompose.router.stack.pop
 import com.arkivanov.decompose.router.stack.push
 import com.arkivanov.decompose.router.stack.stackRouter
@@ -28,7 +28,7 @@ internal class DynamicFeaturesComponent(
             childFactory = ::child,
         )
 
-    override val routerState: Value<RouterState<*, Child>> = router.state
+    override val childStack: Value<ChildStack<*, Child>> = router.stack
 
     private fun child(config: Config, componentContext: ComponentContext): Child =
         when (config) {
diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/dynamicfeature/DynamicFeature.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/dynamicfeature/DynamicFeature.kt
index c16f4faa..d400fe3c 100644
--- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/dynamicfeature/DynamicFeature.kt
+++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/dynamicfeature/DynamicFeature.kt
@@ -1,11 +1,11 @@
 package com.arkivanov.sample.shared.dynamicfeatures.dynamicfeature
 
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 import com.arkivanov.decompose.value.Value
 
 interface DynamicFeature<out T : Any> {
 
-    val routerState: Value<RouterState<*, Child<T>>>
+    val childStack: Value<ChildStack<*, Child<T>>>
 
     sealed interface Child<out T : Any> {
         class Loading(val name: String) : Child<Nothing>
diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/dynamicfeature/DynamicFeatureComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/dynamicfeature/DynamicFeatureComponent.kt
index 3688027c..ee27830a 100644
--- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/dynamicfeature/DynamicFeatureComponent.kt
+++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/dynamicfeature/DynamicFeatureComponent.kt
@@ -1,7 +1,7 @@
 package com.arkivanov.sample.shared.dynamicfeatures.dynamicfeature
 
 import com.arkivanov.decompose.ComponentContext
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 import com.arkivanov.decompose.router.stack.StackRouter
 import com.arkivanov.decompose.router.stack.replaceCurrent
 import com.arkivanov.decompose.router.stack.stackRouter
@@ -26,7 +26,7 @@ internal class DynamicFeatureComponent<out T : Any>(
             childFactory = ::child,
         )
 
-    override val routerState: Value<RouterState<*, Child<T>>> = router.state
+    override val childStack: Value<ChildStack<*, Child<T>>> = router.stack
 
     private fun child(config: Config, componentContext: ComponentContext): Child<T> =
         when (config) {
diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/multipane/DetailsRouter.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/multipane/DetailsRouter.kt
index 3713f72f..def05d80 100644
--- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/multipane/DetailsRouter.kt
+++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/multipane/DetailsRouter.kt
@@ -1,7 +1,7 @@
 package com.arkivanov.sample.shared.multipane
 
 import com.arkivanov.decompose.ComponentContext
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 import com.arkivanov.decompose.router.stack.activeChild
 import com.arkivanov.decompose.router.stack.navigate
 import com.arkivanov.decompose.router.stack.popWhile
@@ -29,7 +29,7 @@ internal class DetailsRouter(
             childFactory = ::createChild,
         )
 
-    val state: Value<RouterState<Config, DetailsChild>> = router.state
+    val stack: Value<ChildStack<Config, DetailsChild>> = router.stack
 
     private fun createChild(config: Config, componentContext: ComponentContext): DetailsChild =
         when (config) {
diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/multipane/ListRouter.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/multipane/ListRouter.kt
index f3d33715..4ad34c80 100644
--- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/multipane/ListRouter.kt
+++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/multipane/ListRouter.kt
@@ -1,7 +1,7 @@
 package com.arkivanov.sample.shared.multipane
 
 import com.arkivanov.decompose.ComponentContext
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 import com.arkivanov.decompose.router.stack.activeChild
 import com.arkivanov.decompose.router.stack.pop
 import com.arkivanov.decompose.router.stack.push
@@ -29,7 +29,7 @@ internal class ListRouter(
             childFactory = ::createChild,
         )
 
-    val state: Value<RouterState<Config, ListChild>> = router.state
+    val stack: Value<ChildStack<Config, ListChild>> = router.stack
 
     private fun createChild(config: Config, componentContext: ComponentContext): ListChild =
         when (config) {
diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/multipane/MultiPane.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/multipane/MultiPane.kt
index 1705909f..e55191e7 100644
--- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/multipane/MultiPane.kt
+++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/multipane/MultiPane.kt
@@ -1,6 +1,6 @@
 package com.arkivanov.sample.shared.multipane
 
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 import com.arkivanov.decompose.value.Value
 import com.arkivanov.sample.shared.multipane.details.ArticleDetails
 import com.arkivanov.sample.shared.multipane.list.ArticleList
@@ -8,8 +8,8 @@ import com.arkivanov.sample.shared.multipane.list.ArticleList
 interface MultiPane {
 
     val models: Value<Model>
-    val listRouterState: Value<RouterState<*, ListChild>>
-    val detailsRouterState: Value<RouterState<*, DetailsChild>>
+    val listChildStack: Value<ChildStack<*, ListChild>>
+    val detailsChildStack: Value<ChildStack<*, DetailsChild>>
 
     fun setMultiPane(isMultiPane: Boolean)
 
diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/multipane/MultiPaneComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/multipane/MultiPaneComponent.kt
index ff707f50..ae22a010 100644
--- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/multipane/MultiPaneComponent.kt
+++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/multipane/MultiPaneComponent.kt
@@ -1,7 +1,7 @@
 package com.arkivanov.sample.shared.multipane
 
 import com.arkivanov.decompose.ComponentContext
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 import com.arkivanov.decompose.value.MutableValue
 import com.arkivanov.decompose.value.Value
 import com.arkivanov.decompose.value.observe
@@ -32,7 +32,7 @@ internal class MultiPaneComponent(
             onArticleSelected = ::onArticleSelected
         )
 
-    override val listRouterState: Value<RouterState<*, ListChild>> = listRouter.state
+    override val listChildStack: Value<ChildStack<*, ListChild>> = listRouter.stack
 
     private val detailsRouter =
         DetailsRouter(
@@ -42,7 +42,7 @@ internal class MultiPaneComponent(
             onFinished = ::closeDetailsAndShowList
         )
 
-    override val detailsRouterState: Value<RouterState<*, DetailsChild>> = detailsRouter.state
+    override val detailsChildStack: Value<ChildStack<*, DetailsChild>> = detailsRouter.stack
 
     init {
         backPressedHandler.register {
@@ -54,7 +54,7 @@ internal class MultiPaneComponent(
             }
         }
 
-        detailsRouter.state.observe(lifecycle) {
+        detailsRouter.stack.observe(lifecycle) {
             selectedArticleIdSubject.onNext(it.active.configuration.getArticleId())
         }
     }
diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/root/Root.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/root/Root.kt
index 9ab5d8e5..6e6e8974 100644
--- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/root/Root.kt
+++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/root/Root.kt
@@ -1,6 +1,6 @@
 package com.arkivanov.sample.shared.root
 
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 import com.arkivanov.decompose.value.Value
 import com.arkivanov.sample.shared.counters.Counters
 import com.arkivanov.sample.shared.dynamicfeatures.DynamicFeatures
@@ -8,7 +8,7 @@ import com.arkivanov.sample.shared.multipane.MultiPane
 
 interface Root {
 
-    val routerState: Value<RouterState<*, Child>>
+    val childStack: Value<ChildStack<*, Child>>
 
     fun onCountersTabClicked()
     fun onMultiPaneTabClicked()
diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/root/RootComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/root/RootComponent.kt
index 36e1ca6f..b528033c 100644
--- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/root/RootComponent.kt
+++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/root/RootComponent.kt
@@ -2,7 +2,7 @@ package com.arkivanov.sample.shared.root
 
 import com.arkivanov.decompose.ComponentContext
 import com.arkivanov.decompose.ExperimentalDecomposeApi
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 import com.arkivanov.decompose.router.stack.StackRouter
 import com.arkivanov.decompose.router.stack.bringToFront
 import com.arkivanov.decompose.router.stack.stackRouter
@@ -33,7 +33,7 @@ class RootComponent constructor(
             childFactory = ::child,
         )
 
-    override val routerState: Value<RouterState<*, Child>> = router.state
+    override val childStack: Value<ChildStack<*, Child>> = router.stack
 
     init {
         webHistoryController?.attach(
diff --git a/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/counters/CountersContent.kt b/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/counters/CountersContent.kt
index d45c6025..b0e4e85c 100644
--- a/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/counters/CountersContent.kt
+++ b/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/counters/CountersContent.kt
@@ -20,8 +20,8 @@ import mui.system.sx
 import react.FC
 
 val CountersContent: FC<RProps<Counters>> = FC { props ->
-    val firstRouterState by props.component.firstRouterState.useAsState()
-    val secondRouterState by props.component.secondRouterState.useAsState()
+    val firstChildStack by props.component.firstChildStack.useAsState()
+    val secondChildStack by props.component.secondChildStack.useAsState()
 
     Box {
         sx {
@@ -48,8 +48,8 @@ val CountersContent: FC<RProps<Counters>> = FC { props ->
                     padding = 16.px
                 }
 
-                componentContent(component = firstRouterState.active.instance, content = CounterContent)
-                componentContent(component = secondRouterState.active.instance, content = CounterContent)
+                componentContent(component = firstChildStack.active.instance, content = CounterContent)
+                componentContent(component = secondChildStack.active.instance, content = CounterContent)
             }
         }
     }
diff --git a/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/DynamicFeaturesContent.kt b/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/DynamicFeaturesContent.kt
index c0987004..30a8c200 100644
--- a/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/DynamicFeaturesContent.kt
+++ b/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/DynamicFeaturesContent.kt
@@ -20,7 +20,7 @@ import mui.system.sx
 import react.FC
 
 val DynamicFeaturesContent: FC<RProps<DynamicFeatures>> = FC { props ->
-    val routerState by props.component.routerState.useAsState()
+    val childStack by props.component.childStack.useAsState()
 
     Box {
         sx {
@@ -39,7 +39,7 @@ val DynamicFeaturesContent: FC<RProps<DynamicFeatures>> = FC { props ->
                 padding = 16.px
             }
 
-            when (val child = routerState.active.instance) {
+            when (val child = childStack.active.instance) {
                 is Feature1Child ->
                     componentContent(
                         component = child.feature1,
diff --git a/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/dynamicfeature/DynamicFeatureContent.kt b/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/dynamicfeature/DynamicFeatureContent.kt
index 0e23dfbe..3f681895 100644
--- a/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/dynamicfeature/DynamicFeatureContent.kt
+++ b/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/dynamicfeatures/dynamicfeature/DynamicFeatureContent.kt
@@ -10,9 +10,9 @@ import react.FC
 fun <T : Any> DynamicFeatureContent(
     content: ChildrenBuilder.(T) -> Unit,
 ): FC<RProps<DynamicFeature<T>>> = FC { props ->
-    val routerState by props.component.routerState.useAsState()
+    val childStack by props.component.childStack.useAsState()
 
-    when (val child = routerState.active.instance) {
+    when (val child = childStack.active.instance) {
         is DynamicFeature.Child.Loading -> Typography { +"Loading ${child.name}" }
         is DynamicFeature.Child.Feature -> content(child.feature)
         is DynamicFeature.Child.Error -> Typography { +"Error loading ${child.name}" }
diff --git a/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/multipane/MultiPaneContent.kt b/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/multipane/MultiPaneContent.kt
index 24845e3e..5447e309 100644
--- a/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/multipane/MultiPaneContent.kt
+++ b/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/multipane/MultiPaneContent.kt
@@ -24,8 +24,8 @@ private const val MULTI_PANE_WIDTH_THRESHOLD = 960
 
 val MultiPaneContent: FC<RProps<MultiPane>> = FC { props ->
     val model by props.component.models.useAsState()
-    val listRouterState by props.component.listRouterState.useAsState()
-    val detailsRouterState by props.component.detailsRouterState.useAsState()
+    val listChildStack by props.component.listChildStack.useAsState()
+    val detailsChildStack by props.component.detailsChildStack.useAsState()
 
     fun onWindowResized() {
         props.component.setMultiPane(window.innerWidth >= MULTI_PANE_WIDTH_THRESHOLD)
@@ -41,13 +41,13 @@ val MultiPaneContent: FC<RProps<MultiPane>> = FC { props ->
 
     if (model.isMultiPane) {
         DoublePane {
-            listChild = listRouterState.active.instance
-            detailsChild = detailsRouterState.active.instance
+            listChild = listChildStack.active.instance
+            detailsChild = detailsChildStack.active.instance
         }
     } else {
         SinglePane {
-            listChild = listRouterState.active.instance
-            detailsChild = detailsRouterState.active.instance
+            listChild = listChildStack.active.instance
+            detailsChild = detailsChildStack.active.instance
         }
     }
 }
diff --git a/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/root/RootContent.kt b/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/root/RootContent.kt
index b7b22ff5..c0aae41f 100644
--- a/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/root/RootContent.kt
+++ b/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/root/RootContent.kt
@@ -28,7 +28,7 @@ import react.ReactNode
 import react.create
 
 var RootContent: FC<RProps<Root>> = FC { props ->
-    val routerState by props.component.routerState.useAsState()
+    val childStack by props.component.childStack.useAsState()
 
     Box {
         sx {
@@ -50,7 +50,7 @@ var RootContent: FC<RProps<Root>> = FC { props ->
                 overflowY = Overflow.clip
             }
 
-            when (val child = routerState.active.instance) {
+            when (val child = childStack.active.instance) {
                 is CountersChild -> componentContent(component = child.component, content = CountersContent)
                 is MultiPaneChild -> componentContent(component = child.component, content = MultiPaneContent)
                 is DynamicFeaturesChild -> componentContent(component = child.component, content = DynamicFeaturesContent)
@@ -65,7 +65,7 @@ var RootContent: FC<RProps<Root>> = FC { props ->
 
             showLabels = true
 
-            value = when (routerState.active.instance) {
+            value = when (childStack.active.instance) {
                 is CountersChild -> TabItem.COUNTERS
                 is MultiPaneChild -> TabItem.MULTI_PANE
                 is DynamicFeaturesChild -> TabItem.DYNAMIC_FEATURES


Test patch:
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/ChildStackTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/ChildStackTest.kt
new file mode 100644
index 00000000..8768f15c
--- /dev/null
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/ChildStackTest.kt
@@ -0,0 +1,33 @@
+package com.arkivanov.decompose.router.stack
+
+import com.arkivanov.decompose.Child
+import kotlin.test.Test
+import kotlin.test.assertContentEquals
+
+@Suppress("TestFunctionName")
+class ChildStackTest {
+
+    @Test
+    fun GIVEN_back_stack_empty_WHEN_items_THEN_returns_list_with_active_child() {
+        val activeChild = child(configuration = "A")
+        val stack = ChildStack(active = activeChild, backStack = emptyList())
+
+        val items = stack.items
+
+        assertContentEquals(listOf(activeChild), items)
+    }
+
+    @Test
+    fun GIVEN_back_stack_not_empty_WHEN_items_THEN_returns_list_with_back_stack_and_active_child() {
+        val activeChild = child(configuration = "A")
+        val backStack = List(3) { child(configuration = it.toString()) }
+        val stack = ChildStack(active = activeChild, backStack = backStack)
+
+        val items = stack.items
+
+        assertContentEquals(backStack + activeChild, items)
+    }
+
+    private fun child(configuration: String): Child.Created<String, String> =
+        Child.Created(configuration = configuration, instance = configuration)
+}
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterBringToFrontTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterBringToFrontTest.kt
index d2379d2f..4969971a 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterBringToFrontTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterBringToFrontTest.kt
@@ -12,7 +12,7 @@ class RouterBringToFrontTest {
 
         router.bringToFront(Config.C(0))
 
-        assertEquals(listOf(Config.A, Config.B, Config.C(0)), router.stack)
+        assertEquals(listOf(Config.A, Config.B, Config.C(0)), router.configs)
     }
 
     @Test
@@ -21,7 +21,7 @@ class RouterBringToFrontTest {
 
         router.bringToFront(Config.C(0))
 
-        assertEquals(listOf(Config.A, Config.B, Config.C(0)), router.stack)
+        assertEquals(listOf(Config.A, Config.B, Config.C(0)), router.configs)
     }
 
     @Test
@@ -30,7 +30,7 @@ class RouterBringToFrontTest {
 
         router.bringToFront(Config.C(0))
 
-        assertEquals(listOf(Config.A, Config.B, Config.C(0)), router.stack)
+        assertEquals(listOf(Config.A, Config.B, Config.C(0)), router.configs)
     }
 
     @Test
@@ -39,7 +39,7 @@ class RouterBringToFrontTest {
 
         router.bringToFront(Config.C(0))
 
-        assertEquals(listOf(Config.A, Config.B, Config.C(0)), router.stack)
+        assertEquals(listOf(Config.A, Config.B, Config.C(0)), router.configs)
     }
 
     @Test
@@ -48,7 +48,7 @@ class RouterBringToFrontTest {
 
         router.bringToFront(Config.C(1))
 
-        assertEquals(listOf(Config.A, Config.B, Config.C(1)), router.stack)
+        assertEquals(listOf(Config.A, Config.B, Config.C(1)), router.configs)
     }
 
     @Test
@@ -57,7 +57,7 @@ class RouterBringToFrontTest {
 
         router.bringToFront(Config.C(1))
 
-        assertEquals(listOf(Config.A, Config.B, Config.C(1)), router.stack)
+        assertEquals(listOf(Config.A, Config.B, Config.C(1)), router.configs)
     }
 
     @Test
@@ -66,7 +66,7 @@ class RouterBringToFrontTest {
 
         router.bringToFront(Config.C(1))
 
-        assertEquals(listOf(Config.A, Config.B, Config.C(1)), router.stack)
+        assertEquals(listOf(Config.A, Config.B, Config.C(1)), router.configs)
     }
 
     @Test
@@ -75,7 +75,7 @@ class RouterBringToFrontTest {
 
         router.bringToFront(Config.C(1))
 
-        assertEquals(listOf(Config.A, Config.B, Config.C(1)), router.stack)
+        assertEquals(listOf(Config.A, Config.B, Config.C(1)), router.configs)
     }
 
     private sealed class Config {
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterPopTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterPopTest.kt
index 69b7385a..d0e5fca5 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterPopTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterPopTest.kt
@@ -14,7 +14,7 @@ class RouterPopTest {
 
         router.pop()
 
-        assertEquals(listOf(Config.A), router.stack)
+        assertEquals(listOf(Config.A), router.configs)
     }
 
     @Test
@@ -33,7 +33,7 @@ class RouterPopTest {
 
         router.pop()
 
-        assertEquals(listOf(Config.A), router.stack)
+        assertEquals(listOf(Config.A), router.configs)
     }
 
 
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterPopWhileTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterPopWhileTest.kt
index 7c34d23a..9c68383a 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterPopWhileTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterPopWhileTest.kt
@@ -13,7 +13,7 @@ class RouterPopWhileTest {
 
         router.popWhile { it != 2 }
 
-        assertEquals(listOf(1, 2), router.stack)
+        assertEquals(listOf(1, 2), router.configs)
     }
 
     @Test
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterPushTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterPushTest.kt
index 5f8048c7..4ad17aa7 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterPushTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterPushTest.kt
@@ -13,7 +13,7 @@ class RouterPushTest {
 
         router.push(3)
 
-        assertEquals(listOf(1, 2, 3), router.stack)
+        assertEquals(listOf(1, 2, 3), router.configs)
     }
 
     @Test
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterReplaceCurrentTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterReplaceCurrentTest.kt
index 911b2385..6f6b0c42 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterReplaceCurrentTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterReplaceCurrentTest.kt
@@ -13,7 +13,7 @@ class RouterReplaceCurrentTest {
 
         router.replaceCurrent(4)
 
-        assertEquals(listOf(1, 2, 4), router.stack)
+        assertEquals(listOf(1, 2, 4), router.configs)
     }
 
     @Test
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterTest.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterTest.kt
index 1f36d1e9..973840a8 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterTest.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/RouterTest.kt
@@ -147,10 +147,10 @@ class RouterTest {
             )
 
         private val StackRouter<Config, *>.configurations: List<Config>
-            get() = state.value.configurations
+            get() = stack.value.configurations
 
-        private val RouterState<Config, *>.configurations: List<Config>
-            get() = backStack.map { it.configuration } + active.configuration
+        private val ChildStack<Config, *>.configurations: List<Config>
+            get() = items.map { it.configuration }
     }
 
     @Parcelize
diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/TestRouter.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/TestRouter.kt
index 165a45f0..8eb97cee 100644
--- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/TestRouter.kt
+++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/router/stack/TestRouter.kt
@@ -5,16 +5,16 @@ import com.arkivanov.decompose.value.MutableValue
 
 class TestRouter<C : Any>(stack: List<C>) : StackRouter<C, Any> {
 
-    override val state: MutableValue<RouterState<C, Any>> = MutableValue(stack.toRouterState())
+    override val stack: MutableValue<ChildStack<C, Any>> = MutableValue(stack.toRouterState())
 
-    var stack: List<C>
-        get() = state.value.backStack.map(Child<C, *>::configuration) + state.value.active.configuration
+    var configs: List<C>
+        get() = stack.value.items.map { it.configuration }
         set(value) {
-            state.value = value.toRouterState()
+            stack.value = value.toRouterState()
         }
 
-    private fun List<C>.toRouterState(): RouterState<C, Any> =
-        RouterState<C, Any>(
+    private fun List<C>.toRouterState(): ChildStack<C, Any> =
+        ChildStack<C, Any>(
             active = Child.Created(
                 configuration = last(),
                 instance = last(),
@@ -28,9 +28,9 @@ class TestRouter<C : Any>(stack: List<C>) : StackRouter<C, Any> {
         )
 
     override fun navigate(transformer: (stack: List<C>) -> List<C>, onComplete: (newStack: List<C>, oldStack: List<C>) -> Unit) {
-        val oldStack = stack
-        val newStack = transformer(stack)
-        stack = newStack
-        onComplete(newStack, oldStack)
+        val oldConfigs = this.configs
+        val newConfigs = transformer(this.configs)
+        this.configs = newConfigs
+        onComplete(newConfigs, oldConfigs)
     }
 }
diff --git a/extensions-compose-jetbrains/src/jvmTest/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/ChildrenTest.kt b/extensions-compose-jetbrains/src/jvmTest/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/ChildrenTest.kt
index f9b2147c..abbf22bb 100644
--- a/extensions-compose-jetbrains/src/jvmTest/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/ChildrenTest.kt
+++ b/extensions-compose-jetbrains/src/jvmTest/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/stack/ChildrenTest.kt
@@ -22,7 +22,7 @@ import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.plus
 import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.scale
 import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.slide
 import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.stackAnimation
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
 import org.junit.Rule
@@ -106,9 +106,9 @@ class ChildrenTest(
         }
     }
 
-    private suspend fun setContent(state: State<RouterState<Config, Config>>) {
+    private suspend fun setContent(state: State<ChildStack<Config, Config>>) {
         composeRule.setContent {
-            Children(routerState = state.value, animation = animation) { child ->
+            Children(stack = state.value, animation = animation) { child ->
                 when (child.configuration) {
                     Config.A -> Child(name = "A")
                     Config.B -> Child(name = "B")
@@ -119,8 +119,8 @@ class ChildrenTest(
         runOnIdle {}
     }
 
-    private fun routerState(activeConfig: Config, backstack: List<Config> = emptyList()): RouterState<Config, Config> =
-        RouterState(
+    private fun routerState(activeConfig: Config, backstack: List<Config> = emptyList()): ChildStack<Config, Config> =
+        ChildStack(
             active = Child.Created(configuration = activeConfig, instance = activeConfig),
             backStack = backstack.map { Child.Destroyed(configuration = it) },
         )
diff --git a/extensions-compose-jetpack/src/androidTest/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/ChildrenTest.kt b/extensions-compose-jetpack/src/androidTest/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/ChildrenTest.kt
index a39f4d57..1442531a 100644
--- a/extensions-compose-jetpack/src/androidTest/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/ChildrenTest.kt
+++ b/extensions-compose-jetpack/src/androidTest/java/com/arkivanov/decompose/extensions/compose/jetpack/stack/ChildrenTest.kt
@@ -22,7 +22,7 @@ import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.plus
 import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.scale
 import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.slide
 import com.arkivanov.decompose.extensions.compose.jetpack.stack.animation.stackAnimation
-import com.arkivanov.decompose.router.stack.RouterState
+import com.arkivanov.decompose.router.stack.ChildStack
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -94,9 +94,9 @@ class ChildrenTest(
         composeRule.onNodeWithText(text = "ChildB=0").assertExists()
     }
 
-    private fun setContent(state: State<RouterState<Config, Config>>) {
+    private fun setContent(stack: State<ChildStack<Config, Config>>) {
         composeRule.setContent {
-            Children(routerState = state.value, animation = animation) { child ->
+            Children(stack = stack.value, animation = animation) { child ->
                 when (child.configuration) {
                     Config.A -> Child(name = "A")
                     Config.B -> Child(name = "B")
@@ -107,8 +107,8 @@ class ChildrenTest(
         runOnIdle {}
     }
 
-    private fun routerState(activeConfig: Config, backstack: List<Config> = emptyList()): RouterState<Config, Config> =
-        RouterState(
+    private fun routerState(activeConfig: Config, backstack: List<Config> = emptyList()): ChildStack<Config, Config> =
+        ChildStack(
             active = Child.Created(configuration = activeConfig, instance = activeConfig),
             backStack = backstack.map { Child.Destroyed(configuration = it) }
         )