From c4e5fc3cdbb72e7e334d1728db25c9c21d3f1aee Mon Sep 17 00:00:00 2001 From: y9san9 Date: Fri, 31 May 2024 17:51:29 +0300 Subject: [PATCH] feat: added support for react --- .../js-browser-library-convention.gradle.kts | 12 +++++ gradle/libs.versions.toml | 6 ++- .../ksm/coroutines/StateControllerBuilder.kt | 12 +++++ .../navigation/compose/ComposeController.kt | 2 +- .../compose/RememberStateController.kt | 12 +++-- .../navigation/compose/StateBuilderScope.kt | 6 +-- .../ksm/navigation/compose/example/Example.kt | 18 +++---- ...gationStateHost.kt => ComposeStateHost.kt} | 4 +- .../navigation/compose/plugin/ComposeEntry.kt | 1 - .../compose/plugin/ComposePlugin.kt | 1 + .../compose/route/ComposeBuilderScope.kt | 24 +++++++++ .../compose/route/ComposeController.kt | 11 +++++ .../compose/route/ComposeRouteScope.kt | 17 +++++++ .../ksm/navigation/mdi/StateBuilderScope.kt | 2 +- navigation/navigation-react/build.gradle.kts | 11 +++++ .../ksm/navigation/react/ReactController.kt | 21 ++++++++ .../react/ReactControllerBuilder.kt | 34 +++++++++++++ .../navigation/react/UseReactController.kt | 46 +++++++++++++++++ .../navigation/react/example/ReactExample.kt | 31 ++++++++++++ .../react/host/ReactControllerProps.kt | 11 +++++ .../react/host/ReactStateHostComponent.kt | 47 ++++++++++++++++++ .../navigation/react/observable/Observable.kt | 23 +++++++++ .../navigation/react/observable/Observer.kt | 5 ++ .../react/observable/ReactStateConverter.kt | 23 +++++++++ .../navigation/react/plugin/ReactComponent.kt | 21 ++++++++ .../ksm/navigation/react/plugin/ReactEntry.kt | 11 +++++ .../navigation/react/plugin/ReactPlugin.kt | 49 +++++++++++++++++++ .../react/plugin/ReactStateController.kt | 12 +++++ .../react/route/ReactBuilderScope.kt | 31 ++++++++++++ .../navigation/react/route/ReactController.kt | 11 +++++ .../navigation/react/route/ReactRouteScope.kt | 21 ++++++++ .../navigation/NavigationControllerBuilder.kt | 2 +- .../{StateBuilderDSL.kt => StateRouteDSL.kt} | 2 +- .../route/NavigationControllerBuilder.kt | 4 +- .../ksm/navigation/route/StateBuilderScope.kt | 9 ++++ .../ksm/navigation/route/StateContext.kt | 24 +++++++++ .../ksm/navigation/route/StateRouteScope.kt | 9 ++++ .../route/plugin/StateRouteEntry.kt | 20 ++++++++ .../route/plugin/StateRoutePlugin.kt | 35 ++++++++----- .../route/plugin/StateRouteStateController.kt | 19 +++++++ .../navigation/state/name/StateRouteScope.kt | 12 ++--- .../state/route/NavigationController.kt | 7 --- .../state/route/StateBuilderScope.kt | 7 --- .../navigation/state/route/StateContext.kt | 9 ---- .../navigation/state/route/StateRouteScope.kt | 26 ---------- settings.gradle.kts | 1 + .../ksm/viewmodel/ViewModelController.kt | 15 ++++-- 47 files changed, 636 insertions(+), 101 deletions(-) create mode 100644 build-logic/src/main/kotlin/js-browser-library-convention.gradle.kts create mode 100644 kotlinx-coroutines/src/commonMain/kotlin/ksm/coroutines/StateControllerBuilder.kt rename navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/host/{NavigationStateHost.kt => ComposeStateHost.kt} (94%) create mode 100644 navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/route/ComposeBuilderScope.kt create mode 100644 navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/route/ComposeController.kt create mode 100644 navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/route/ComposeRouteScope.kt create mode 100644 navigation/navigation-react/build.gradle.kts create mode 100644 navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/ReactController.kt create mode 100644 navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/ReactControllerBuilder.kt create mode 100644 navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/UseReactController.kt create mode 100644 navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/example/ReactExample.kt create mode 100644 navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/host/ReactControllerProps.kt create mode 100644 navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/host/ReactStateHostComponent.kt create mode 100644 navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/observable/Observable.kt create mode 100644 navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/observable/Observer.kt create mode 100644 navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/observable/ReactStateConverter.kt create mode 100644 navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/plugin/ReactComponent.kt create mode 100644 navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/plugin/ReactEntry.kt create mode 100644 navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/plugin/ReactPlugin.kt create mode 100644 navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/plugin/ReactStateController.kt create mode 100644 navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/route/ReactBuilderScope.kt create mode 100644 navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/route/ReactController.kt create mode 100644 navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/route/ReactRouteScope.kt rename navigation/src/commonMain/kotlin/ksm/navigation/annotation/{StateBuilderDSL.kt => StateRouteDSL.kt} (53%) rename navigation/src/commonMain/kotlin/ksm/navigation/{state => }/route/NavigationControllerBuilder.kt (70%) create mode 100644 navigation/src/commonMain/kotlin/ksm/navigation/route/StateBuilderScope.kt create mode 100644 navigation/src/commonMain/kotlin/ksm/navigation/route/StateContext.kt create mode 100644 navigation/src/commonMain/kotlin/ksm/navigation/route/StateRouteScope.kt create mode 100644 navigation/src/commonMain/kotlin/ksm/navigation/route/plugin/StateRouteEntry.kt rename navigation/src/commonMain/kotlin/ksm/navigation/{state => }/route/plugin/StateRoutePlugin.kt (55%) create mode 100644 navigation/src/commonMain/kotlin/ksm/navigation/route/plugin/StateRouteStateController.kt delete mode 100644 navigation/src/commonMain/kotlin/ksm/navigation/state/route/NavigationController.kt delete mode 100644 navigation/src/commonMain/kotlin/ksm/navigation/state/route/StateBuilderScope.kt delete mode 100644 navigation/src/commonMain/kotlin/ksm/navigation/state/route/StateContext.kt delete mode 100644 navigation/src/commonMain/kotlin/ksm/navigation/state/route/StateRouteScope.kt diff --git a/build-logic/src/main/kotlin/js-browser-library-convention.gradle.kts b/build-logic/src/main/kotlin/js-browser-library-convention.gradle.kts new file mode 100644 index 0000000..f1a262d --- /dev/null +++ b/build-logic/src/main/kotlin/js-browser-library-convention.gradle.kts @@ -0,0 +1,12 @@ +plugins { + kotlin("multiplatform") + id("publication-convention") +} + +kotlin { + explicitApi() + + js(IR) { + browser() + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 97b4d28..fae92c8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,8 +10,9 @@ androidx-navigation = "2.7.7" androidx-lifecycle = "2.7.0" ktgbotapi = "11.0.0" mdi = "0.0.38" +react = "18.3.1-pre.754" -ksm = "0.0.37" +ksm = "0.0.45" [libraries] @@ -29,6 +30,9 @@ ktgbotapi = { module = "dev.inmo:tgbotapi", version.ref = "ktgbotapi" } mdi = { module = "app.meetacy.di:core", version.ref = "mdi" } +react = { module = "org.jetbrains.kotlin-wrappers:kotlin-react", version.ref = "react" } +react-dom = { module = "org.jetbrains.kotlin-wrappers:kotlin-react-dom", version.ref = "react" } + # gradle plugins kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } kotlinx-serialization-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kotlin" } diff --git a/kotlinx-coroutines/src/commonMain/kotlin/ksm/coroutines/StateControllerBuilder.kt b/kotlinx-coroutines/src/commonMain/kotlin/ksm/coroutines/StateControllerBuilder.kt new file mode 100644 index 0000000..b7a48af --- /dev/null +++ b/kotlinx-coroutines/src/commonMain/kotlin/ksm/coroutines/StateControllerBuilder.kt @@ -0,0 +1,12 @@ +package ksm.coroutines + +import kotlinx.coroutines.CoroutineScope +import ksm.annotation.LibraryApi +import ksm.coroutines.plugin.CoroutinesPlugin +import ksm.plugin.PluginController +import ksm.plugin.install + +@OptIn(LibraryApi::class) +public fun PluginController.Builder.installCoroutines(scope: CoroutineScope) { + install(CoroutinesPlugin(scope)) +} diff --git a/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/ComposeController.kt b/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/ComposeController.kt index 78432ec..9851790 100644 --- a/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/ComposeController.kt +++ b/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/ComposeController.kt @@ -13,7 +13,7 @@ public interface ComposeController : NavigationController { public companion object : StateControllerFactory { override val type: KType = typeOf() - override fun wrap(context: StateContext): PluginController { + override fun wrap(context: StateContext): ComposeController { return object : ComposeController { override val context = context } diff --git a/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/RememberStateController.kt b/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/RememberStateController.kt index b007457..883515b 100644 --- a/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/RememberStateController.kt +++ b/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/RememberStateController.kt @@ -3,13 +3,11 @@ package ksm.navigation.compose import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable -import ksm.StateController import ksm.annotation.LibraryApi import ksm.context.StateContext import ksm.navigation.compose.plugin.ComposeSerializationStore import ksm.navigation.compose.wrapper.ComposeWrapper import ksm.navigation.serialization.restore -import ksm.plugin.factory.asController @OptIn(LibraryApi::class) @Composable @@ -23,11 +21,15 @@ public fun rememberComposeController( init = { ComposeSerializationStore() } ) return remember(store) { - object : ComposeController.Builder { + val scope = object : ComposeController.Builder { override var context: StateContext = StateContext.Empty - }.apply { + } + + with(scope) { composeRuntime(store, wrapper) { builder() } context.restore() - }.context.asController() + } + + ComposeController.wrap(scope.context) } } diff --git a/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/StateBuilderScope.kt b/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/StateBuilderScope.kt index 7053308..1ac6bf1 100644 --- a/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/StateBuilderScope.kt +++ b/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/StateBuilderScope.kt @@ -1,14 +1,12 @@ package ksm.navigation.compose import androidx.compose.runtime.Composable -import ksm.StateController -import ksm.navigation.NavigationController import ksm.navigation.compose.plugin.ComposePlugin -import ksm.navigation.state.route.StateBuilderScope +import ksm.navigation.route.StateBuilderScope import ksm.plugin.plugin public fun StateBuilderScope.Content( - block: @Composable NavigationController.() -> Unit + block: @Composable ComposeController.() -> Unit ) { context.plugin(ComposePlugin).setContent(context, block) } diff --git a/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/example/Example.kt b/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/example/Example.kt index f42085b..1e420b4 100644 --- a/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/example/Example.kt +++ b/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/example/Example.kt @@ -3,18 +3,16 @@ package ksm.navigation.compose.example import androidx.compose.runtime.Composable import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow -import ksm.StateController import ksm.navigation.NavigationController import ksm.navigation.compose.Content -import ksm.navigation.compose.host.NavigationStateHost +import ksm.navigation.compose.host.ComposeStateHost import ksm.navigation.compose.rememberComposeController -import ksm.navigation.state.route.StateRouteScope -import ksm.navigation.state.route.states -import ksm.navigation.state.data.receive -import ksm.navigation.state.name.named +import ksm.navigation.compose.route.ComposeRouteScope +import ksm.navigation.compose.route.named +import ksm.navigation.compose.route.states import ksm.navigation.result.* +import ksm.navigation.state.data.receive import ksm.viewmodel.viewModelController -import ksm.viewmodel.viewModelRuntime private class MainViewModel { val actions: Flow = emptyFlow() @@ -40,7 +38,7 @@ private fun AppContent() { details() } - NavigationStateHost( + ComposeStateHost( controller = controller, startStateName = MAIN_SCREEN ) @@ -52,7 +50,7 @@ private fun NavigationController.registerDetailsNavigator( return registerNavigator(DETAILS_SCREEN, handler) } -private fun StateRouteScope.main() = named(MAIN_SCREEN) { +private fun ComposeRouteScope.main() = named(MAIN_SCREEN) { Content { val launcher = registerDetailsNavigator { itemName -> println("Item Picked! $itemName") @@ -64,7 +62,7 @@ private fun StateRouteScope.main() = named(MAIN_SCREEN) { } } -private fun StateRouteScope.details() = named(DETAILS_SCREEN) { +private fun ComposeRouteScope.details() = named(DETAILS_SCREEN) { Content { val parameters: DetailsParameters = receive() diff --git a/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/host/NavigationStateHost.kt b/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/host/ComposeStateHost.kt similarity index 94% rename from navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/host/NavigationStateHost.kt rename to navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/host/ComposeStateHost.kt index e07e260..a74aea1 100644 --- a/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/host/NavigationStateHost.kt +++ b/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/host/ComposeStateHost.kt @@ -13,8 +13,8 @@ import ksm.plugin.factory.asController import ksm.plugin.plugin @Composable -public fun NavigationStateHost( - controller: StateController, +public fun ComposeStateHost( + controller: ComposeController, startStateName: String, modifier: Modifier = Modifier ) { diff --git a/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/plugin/ComposeEntry.kt b/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/plugin/ComposeEntry.kt index 9d273d3..b18c78f 100644 --- a/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/plugin/ComposeEntry.kt +++ b/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/plugin/ComposeEntry.kt @@ -6,7 +6,6 @@ import ksm.navigation.compose.interceptor.ComposeInterceptor internal class ComposeEntry(var interceptor: ComposeInterceptor?) : StateContext.Element { override val key = ComposeEntry - var content: ComposeContent? = null companion object : StateContext.Key diff --git a/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/plugin/ComposePlugin.kt b/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/plugin/ComposePlugin.kt index 1be9a5f..f6689eb 100644 --- a/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/plugin/ComposePlugin.kt +++ b/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/plugin/ComposePlugin.kt @@ -2,6 +2,7 @@ package ksm.navigation.compose.plugin import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf +import ksm.annotation.LibraryApi import ksm.annotation.MutateContext import ksm.context.StateContext import ksm.navigation.compose.ComposeController diff --git a/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/route/ComposeBuilderScope.kt b/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/route/ComposeBuilderScope.kt new file mode 100644 index 0000000..0238efc --- /dev/null +++ b/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/route/ComposeBuilderScope.kt @@ -0,0 +1,24 @@ +package ksm.navigation.compose.route + +import androidx.compose.runtime.Composable +import ksm.context.StateContext +import ksm.navigation.compose.ComposeController +import ksm.navigation.compose.plugin.ComposePlugin +import ksm.navigation.route.StateBuilderScope +import ksm.plugin.plugin + +public fun ComposeBuilderScope(context: StateContext): ComposeBuilderScope { + return object : ComposeBuilderScope { + override val context = context + } +} + +public interface ComposeBuilderScope : StateBuilderScope + +@Suppress("FunctionName") +public fun ComposeBuilderScope.Content(content: @Composable ComposeController.() -> Unit) { + context.plugin(ComposePlugin).setContent( + context = context, + content = content + ) +} diff --git a/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/route/ComposeController.kt b/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/route/ComposeController.kt new file mode 100644 index 0000000..6b8c183 --- /dev/null +++ b/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/route/ComposeController.kt @@ -0,0 +1,11 @@ +package ksm.navigation.compose.route + +import ksm.navigation.compose.ComposeController +import ksm.navigation.route.plugin.StateRoutePlugin +import ksm.plugin.plugin + +public fun ComposeController.states(block: ComposeRouteScope.() -> Unit) { + context.plugin(StateRoutePlugin).states(context) { context -> + ComposeRouteScope(context).apply(block) + } +} diff --git a/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/route/ComposeRouteScope.kt b/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/route/ComposeRouteScope.kt new file mode 100644 index 0000000..98e7d56 --- /dev/null +++ b/navigation/navigation-compose/src/main/kotlin/ksm/navigation/compose/route/ComposeRouteScope.kt @@ -0,0 +1,17 @@ +package ksm.navigation.compose.route + +import ksm.context.StateContext +import ksm.navigation.route.StateRouteScope +import ksm.navigation.state.name.interceptNamedRoute + +public fun ComposeRouteScope(context: StateContext): ComposeRouteScope { + return object : ComposeRouteScope { + override val context = context + } +} + +public interface ComposeRouteScope : StateRouteScope + +public inline fun ComposeRouteScope.named(name: String, block: ComposeBuilderScope.() -> Unit) { + context.interceptNamedRoute(name) { ComposeBuilderScope(context).block() } +} diff --git a/navigation/navigation-mdi/src/commonMain/kotlin/ksm/navigation/mdi/StateBuilderScope.kt b/navigation/navigation-mdi/src/commonMain/kotlin/ksm/navigation/mdi/StateBuilderScope.kt index b46feb1..a1c0e3f 100644 --- a/navigation/navigation-mdi/src/commonMain/kotlin/ksm/navigation/mdi/StateBuilderScope.kt +++ b/navigation/navigation-mdi/src/commonMain/kotlin/ksm/navigation/mdi/StateBuilderScope.kt @@ -1,7 +1,7 @@ package ksm.navigation.mdi import app.meetacy.di.DI -import ksm.navigation.state.route.StateBuilderScope +import ksm.navigation.route.StateBuilderScope public var StateBuilderScope.di: DI get() = context.di diff --git a/navigation/navigation-react/build.gradle.kts b/navigation/navigation-react/build.gradle.kts new file mode 100644 index 0000000..ab3082b --- /dev/null +++ b/navigation/navigation-react/build.gradle.kts @@ -0,0 +1,11 @@ +plugins { + id("js-browser-library-convention") +} + +version = libs.versions.ksm.get() + +dependencies { + commonMainApi(projects.navigation) + jsMainImplementation(libs.react) + jsMainImplementation(libs.react.dom) +} diff --git a/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/ReactController.kt b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/ReactController.kt new file mode 100644 index 0000000..87e20c9 --- /dev/null +++ b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/ReactController.kt @@ -0,0 +1,21 @@ +package ksm.navigation.react + +import ksm.context.StateContext +import ksm.navigation.NavigationController +import ksm.plugin.factory.StateControllerFactory +import kotlin.reflect.KType +import kotlin.reflect.typeOf + +public interface ReactController : NavigationController { + public interface Builder : NavigationController.Builder + + public companion object : StateControllerFactory { + override val type: KType = typeOf() + + override fun wrap(context: StateContext): ReactController { + return object : ReactController { + override val context = context + } + } + } +} diff --git a/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/ReactControllerBuilder.kt b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/ReactControllerBuilder.kt new file mode 100644 index 0000000..c18dda2 --- /dev/null +++ b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/ReactControllerBuilder.kt @@ -0,0 +1,34 @@ +package ksm.navigation.react + +import ksm.annotation.LibraryApi +import ksm.context.StateContext +import ksm.navigation.navigationRuntime +import ksm.navigation.react.observable.ObservableState +import ksm.navigation.react.plugin.ReactPlugin +import ksm.plugin.install + +@LibraryApi +public inline fun ReactController.Builder.reactRuntime( + enableConfiguration: Boolean = true, + enableLifecycle: Boolean = true, + enableFinishOnce: Boolean = true, + enableStateName: Boolean = true, + enableStateParameters: Boolean = true, + enableStack: Boolean = true, + enableStateRoutePlugin: Boolean = true, + block: () -> Unit +) { + navigationRuntime( + controllerFactory = ReactController, + enableConfiguration = enableConfiguration, + enableLifecycle = enableLifecycle, + enableFinishOnce = enableFinishOnce, + enableStateName = enableStateName, + enableStateParameters = enableStateParameters, + enableStack = enableStack, + enableStateRoutePlugin = enableStateRoutePlugin + ) { + install(ReactPlugin) + block() + } +} diff --git a/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/UseReactController.kt b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/UseReactController.kt new file mode 100644 index 0000000..4ec0d1e --- /dev/null +++ b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/UseReactController.kt @@ -0,0 +1,46 @@ +package ksm.navigation.react + +import ksm.annotation.LibraryApi +import ksm.context.StateContext +import react.useMemo + +/** + * Only works inside fc + */ +@OptIn(LibraryApi::class) +public fun useReactController( + enableConfiguration: Boolean = true, + enableLifecycle: Boolean = true, + enableFinishOnce: Boolean = true, + enableStateName: Boolean = true, + enableStateParameters: Boolean = true, + enableStack: Boolean = true, + enableStateRoutePlugin: Boolean = true, + builder: ReactController.Builder.() -> Unit = {} +): ReactController { + return useMemo( + enableConfiguration, + enableLifecycle, + enableFinishOnce, + enableStateName, + enableStateParameters, + enableStack, + enableStateRoutePlugin + ) { + val scope = object : ReactController.Builder { + override var context: StateContext = StateContext.Empty + } + scope.reactRuntime( + enableConfiguration = enableConfiguration, + enableLifecycle = enableLifecycle, + enableFinishOnce = enableFinishOnce, + enableStateName = enableStateName, + enableStateParameters = enableStateParameters, + enableStack = enableStack, + enableStateRoutePlugin = enableStateRoutePlugin + ) { + builder(scope) + } + ReactController.wrap(scope.context) + } +} diff --git a/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/example/ReactExample.kt b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/example/ReactExample.kt new file mode 100644 index 0000000..7cd5fe6 --- /dev/null +++ b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/example/ReactExample.kt @@ -0,0 +1,31 @@ +package ksm.navigation.react.example + +import ksm.navigation.react.host.ReactStateHost +import ksm.navigation.react.host.ReactStateHostComponent +import ksm.navigation.react.route.component +import ksm.navigation.react.route.named +import ksm.navigation.react.route.states +import ksm.navigation.react.useReactController +import react.FC + +private val exampleComponent = FC { + val controller = useReactController() + + controller.states { + named("FirstState") { + component { + + } + } + named("SecondState") { + component { + + } + } + } + + ReactStateHost( + controller = controller, + startStateName = "FirstState" + ) +} diff --git a/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/host/ReactControllerProps.kt b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/host/ReactControllerProps.kt new file mode 100644 index 0000000..aa2872a --- /dev/null +++ b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/host/ReactControllerProps.kt @@ -0,0 +1,11 @@ +package ksm.navigation.react.host + +import ksm.navigation.react.ReactController +import org.w3c.dom.HTMLStyleElement +import react.Props + +public external interface ReactControllerProps : Props { + public var controller: ReactController + public var startStateName: String + public var style: (HTMLStyleElement) -> Unit +} diff --git a/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/host/ReactStateHostComponent.kt b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/host/ReactStateHostComponent.kt new file mode 100644 index 0000000..35cd7b9 --- /dev/null +++ b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/host/ReactStateHostComponent.kt @@ -0,0 +1,47 @@ +package ksm.navigation.react.host + +import ksm.navigation.react.ReactController +import ksm.navigation.react.observable.useState +import ksm.navigation.react.plugin.ReactPlugin +import ksm.navigation.react.plugin.createFunctionalComponent +import ksm.navigation.state.navigate +import ksm.plugin.factory.asController +import ksm.plugin.plugin +import org.w3c.dom.HTMLStyleElement +import react.ChildrenBuilder +import react.FC +import react.create +import react.dom.html.ReactHTML.div +import react.dom.html.ReactHTML.style + +public val ReactStateHostComponent: FC = FC { props -> + val controller = props.controller + + controller.navigate(props.startStateName, Unit) + + div { + style(props.style) + + val plugin = controller.context.plugin(ReactPlugin) + + val (currentContext) = useState(plugin.currentState(controller.context)) + currentContext ?: error("Unreachable state") + + val component = plugin.component(currentContext) + val fc = component.createFunctionalComponent(currentContext.asController()) + +fc + } +} + +@Suppress("FunctionName") +public fun ChildrenBuilder.ReactStateHost( + controller: ReactController, + startStateName: String, + style: (HTMLStyleElement) -> Unit = {} +) { + +ReactStateHostComponent.create { + this.controller = controller + this.startStateName = startStateName + this.style = style + } +} diff --git a/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/observable/Observable.kt b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/observable/Observable.kt new file mode 100644 index 0000000..2748824 --- /dev/null +++ b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/observable/Observable.kt @@ -0,0 +1,23 @@ +package ksm.navigation.react.observable + +public class ObservableState(value: T) { + private val observers = mutableSetOf>() + + public fun addObserver(observer: Observer) { + observers.add(observer) + observer.accept(value) + } + + public fun removeObserver(observer: Observer) { + observers.remove(observer) + } + + public var value: T = value + set(value) { + if (field == value) return + field = value + for (observer in observers) { + observer.accept(value) + } + } +} diff --git a/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/observable/Observer.kt b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/observable/Observer.kt new file mode 100644 index 0000000..6326d97 --- /dev/null +++ b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/observable/Observer.kt @@ -0,0 +1,5 @@ +package ksm.navigation.react.observable + +public fun interface Observer { + public fun accept(value: T) +} diff --git a/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/observable/ReactStateConverter.kt b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/observable/ReactStateConverter.kt new file mode 100644 index 0000000..458176d --- /dev/null +++ b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/observable/ReactStateConverter.kt @@ -0,0 +1,23 @@ +package ksm.navigation.react.observable + +import react.StateInstance +import react.useEffect +import react.useState + +public fun useState(state: ObservableState): StateInstance { + val result = useState(state.value) + + val (value, setValue) = result + + useEffect(value) { + state.value = value + } + + useEffect(state) { + val observer = Observer(setValue::invoke) + state.addObserver(observer) + cleanup { state.removeObserver(observer) } + } + + return result +} diff --git a/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/plugin/ReactComponent.kt b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/plugin/ReactComponent.kt new file mode 100644 index 0000000..11c7d55 --- /dev/null +++ b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/plugin/ReactComponent.kt @@ -0,0 +1,21 @@ +package ksm.navigation.react.plugin + +import ksm.navigation.react.ReactController +import react.* +import react.Props + +public fun interface ReactComponent { + public fun ChildrenBuilder.component(controller: ReactController) +} + +private external interface Props : Props { + var controller: ReactController +} + +public fun ReactComponent.createFunctionalComponent(controller: ReactController): ReactElement<*> { + return FC { props -> + component(props.controller) + }.create { + this.controller = controller + } +} diff --git a/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/plugin/ReactEntry.kt b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/plugin/ReactEntry.kt new file mode 100644 index 0000000..644da1f --- /dev/null +++ b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/plugin/ReactEntry.kt @@ -0,0 +1,11 @@ +package ksm.navigation.react.plugin + +import ksm.context.StateContext + +internal class ReactEntry : StateContext.Element { + override val key = ReactEntry + + var component: ReactComponent? = null + + companion object : StateContext.Key +} diff --git a/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/plugin/ReactPlugin.kt b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/plugin/ReactPlugin.kt new file mode 100644 index 0000000..0aeee24 --- /dev/null +++ b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/plugin/ReactPlugin.kt @@ -0,0 +1,49 @@ +package ksm.navigation.react.plugin + +import ksm.annotation.MutateContext +import ksm.context.StateContext +import ksm.navigation.react.observable.ObservableState +import ksm.plugin.Plugin +import ksm.plugin.configuration.interceptor.ConfigurationInterceptor +import ksm.plugin.configuration.interceptor.addConfigurationInterceptor +import ksm.plugin.lifecycle.addLifecycleInterceptor +import ksm.plugin.lifecycle.interceptor.LifecycleInterceptor +import react.StateInstance + +public object ReactPlugin : Plugin.Singleton { + + @MutateContext + override fun install(context: StateContext): StateContext { + context.addConfigurationInterceptor(Configuration) + return context + ReactStateController() + } + + private object Configuration : ConfigurationInterceptor { + @MutateContext + override fun onConfigure(context: StateContext): StateContext { + context.addLifecycleInterceptor(Lifecycle) + return context + ReactEntry() + } + } + + private object Lifecycle : LifecycleInterceptor { + override fun onCreate(context: StateContext) { + context.require(ReactStateController).currentContext.value = context + } + } + + public fun setComponent( + context: StateContext, + component: ReactComponent + ) { + context.require(ReactEntry).component = component + } + + public fun component(context: StateContext): ReactComponent { + return context.require(ReactEntry).component ?: error("Please set 'component' in state builder") + } + + public fun currentState(context: StateContext): ObservableState { + return context.require(ReactStateController).currentContext + } +} diff --git a/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/plugin/ReactStateController.kt b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/plugin/ReactStateController.kt new file mode 100644 index 0000000..c44c514 --- /dev/null +++ b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/plugin/ReactStateController.kt @@ -0,0 +1,12 @@ +package ksm.navigation.react.plugin + +import ksm.context.StateContext +import ksm.navigation.react.observable.ObservableState + +internal class ReactStateController : StateContext.Element { + override val key = ReactStateController + + val currentContext = ObservableState(value = null) + + companion object : StateContext.Key +} diff --git a/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/route/ReactBuilderScope.kt b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/route/ReactBuilderScope.kt new file mode 100644 index 0000000..fcd374d --- /dev/null +++ b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/route/ReactBuilderScope.kt @@ -0,0 +1,31 @@ +package ksm.navigation.react.route + +import ksm.context.StateContext +import ksm.navigation.annotation.StateRouteDSL +import ksm.navigation.react.plugin.ReactComponent +import ksm.navigation.react.plugin.ReactPlugin +import ksm.navigation.route.StateBuilderScope +import ksm.plugin.plugin +import react.FC +import react.Props +import react.create + +public fun ReactBuilderScope(context: StateContext): ReactBuilderScope { + return object : ReactBuilderScope { + override val context = context + } +} + +@StateRouteDSL +public interface ReactBuilderScope : StateBuilderScope + +public fun ReactBuilderScope.component(component: ReactComponent) { + context.plugin(ReactPlugin).setComponent( + context = context, + component = component + ) +} + +public fun ReactBuilderScope.component(fc: FC) { + component { +fc.create() } +} diff --git a/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/route/ReactController.kt b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/route/ReactController.kt new file mode 100644 index 0000000..be96a50 --- /dev/null +++ b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/route/ReactController.kt @@ -0,0 +1,11 @@ +package ksm.navigation.react.route + +import ksm.navigation.react.ReactController +import ksm.navigation.route.plugin.StateRoutePlugin +import ksm.plugin.plugin + +public fun ReactController.states(block: ReactRouteScope.() -> Unit) { + context.plugin(StateRoutePlugin).states(context) { context -> + ReactRouteScope(context).apply(block) + } +} diff --git a/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/route/ReactRouteScope.kt b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/route/ReactRouteScope.kt new file mode 100644 index 0000000..5c119d9 --- /dev/null +++ b/navigation/navigation-react/src/jsMain/kotlin/ksm/navigation/react/route/ReactRouteScope.kt @@ -0,0 +1,21 @@ +package ksm.navigation.react.route + +import ksm.context.StateContext +import ksm.navigation.annotation.StateRouteDSL +import ksm.navigation.route.StateRouteScope +import ksm.navigation.state.name.interceptNamedRoute + +public fun ReactRouteScope(context: StateContext): ReactRouteScope { + return object : ReactRouteScope { + override val context = context + } +} + +@StateRouteDSL +public interface ReactRouteScope : StateRouteScope + +public inline fun ReactRouteScope.named(name: String, block: ReactBuilderScope.() -> Unit) { + context.interceptNamedRoute(name) { + ReactBuilderScope(context).block() + } +} diff --git a/navigation/src/commonMain/kotlin/ksm/navigation/NavigationControllerBuilder.kt b/navigation/src/commonMain/kotlin/ksm/navigation/NavigationControllerBuilder.kt index e2c58f3..5163db7 100644 --- a/navigation/src/commonMain/kotlin/ksm/navigation/NavigationControllerBuilder.kt +++ b/navigation/src/commonMain/kotlin/ksm/navigation/NavigationControllerBuilder.kt @@ -4,7 +4,7 @@ import ksm.annotation.LibraryApi import ksm.navigation.stack.installStackPlugin import ksm.navigation.state.name.installStateName import ksm.navigation.state.parameters.installStateParameters -import ksm.navigation.state.route.installStateRoute +import ksm.navigation.route.installStateRoute import ksm.plugin.factory.StateControllerFactory import ksm.plugin.pluginRuntime diff --git a/navigation/src/commonMain/kotlin/ksm/navigation/annotation/StateBuilderDSL.kt b/navigation/src/commonMain/kotlin/ksm/navigation/annotation/StateRouteDSL.kt similarity index 53% rename from navigation/src/commonMain/kotlin/ksm/navigation/annotation/StateBuilderDSL.kt rename to navigation/src/commonMain/kotlin/ksm/navigation/annotation/StateRouteDSL.kt index aeb38de..9a7a18b 100644 --- a/navigation/src/commonMain/kotlin/ksm/navigation/annotation/StateBuilderDSL.kt +++ b/navigation/src/commonMain/kotlin/ksm/navigation/annotation/StateRouteDSL.kt @@ -1,4 +1,4 @@ package ksm.navigation.annotation @DslMarker -public annotation class StateBuilderDSL +public annotation class StateRouteDSL diff --git a/navigation/src/commonMain/kotlin/ksm/navigation/state/route/NavigationControllerBuilder.kt b/navigation/src/commonMain/kotlin/ksm/navigation/route/NavigationControllerBuilder.kt similarity index 70% rename from navigation/src/commonMain/kotlin/ksm/navigation/state/route/NavigationControllerBuilder.kt rename to navigation/src/commonMain/kotlin/ksm/navigation/route/NavigationControllerBuilder.kt index 3912e04..7abe34d 100644 --- a/navigation/src/commonMain/kotlin/ksm/navigation/state/route/NavigationControllerBuilder.kt +++ b/navigation/src/commonMain/kotlin/ksm/navigation/route/NavigationControllerBuilder.kt @@ -1,8 +1,8 @@ -package ksm.navigation.state.route +package ksm.navigation.route import ksm.annotation.LibraryApi import ksm.navigation.NavigationController -import ksm.navigation.state.route.plugin.StateRoutePlugin +import ksm.navigation.route.plugin.StateRoutePlugin import ksm.plugin.install @OptIn(LibraryApi::class) diff --git a/navigation/src/commonMain/kotlin/ksm/navigation/route/StateBuilderScope.kt b/navigation/src/commonMain/kotlin/ksm/navigation/route/StateBuilderScope.kt new file mode 100644 index 0000000..435a190 --- /dev/null +++ b/navigation/src/commonMain/kotlin/ksm/navigation/route/StateBuilderScope.kt @@ -0,0 +1,9 @@ +package ksm.navigation.route + +import ksm.context.StateContext +import ksm.navigation.annotation.StateRouteDSL + +@StateRouteDSL +public interface StateBuilderScope { + public val context: StateContext +} diff --git a/navigation/src/commonMain/kotlin/ksm/navigation/route/StateContext.kt b/navigation/src/commonMain/kotlin/ksm/navigation/route/StateContext.kt new file mode 100644 index 0000000..7cff7d7 --- /dev/null +++ b/navigation/src/commonMain/kotlin/ksm/navigation/route/StateContext.kt @@ -0,0 +1,24 @@ +package ksm.navigation.route + +import ksm.context.StateContext +import ksm.navigation.route.plugin.StateRoutePlugin +import ksm.plugin.plugin + +public val StateContext.routeIntercepted: Boolean get() { + return plugin(StateRoutePlugin).routeIntercepted(context = this) +} + +public fun StateContext.interceptRoute() { + plugin(StateRoutePlugin).interceptRoute(context = this) +} + +public inline fun StateContext.interceptRoute( + predicate: () -> Boolean, + block: () -> Unit +) { + if (predicate()) { + interceptRoute() + block() + } +} + diff --git a/navigation/src/commonMain/kotlin/ksm/navigation/route/StateRouteScope.kt b/navigation/src/commonMain/kotlin/ksm/navigation/route/StateRouteScope.kt new file mode 100644 index 0000000..7c96b81 --- /dev/null +++ b/navigation/src/commonMain/kotlin/ksm/navigation/route/StateRouteScope.kt @@ -0,0 +1,9 @@ +package ksm.navigation.route + +import ksm.context.StateContext +import ksm.navigation.annotation.StateRouteDSL + +@StateRouteDSL +public interface StateRouteScope { + public val context: StateContext +} diff --git a/navigation/src/commonMain/kotlin/ksm/navigation/route/plugin/StateRouteEntry.kt b/navigation/src/commonMain/kotlin/ksm/navigation/route/plugin/StateRouteEntry.kt new file mode 100644 index 0000000..20fc8ec --- /dev/null +++ b/navigation/src/commonMain/kotlin/ksm/navigation/route/plugin/StateRouteEntry.kt @@ -0,0 +1,20 @@ +package ksm.navigation.route.plugin + +import ksm.context.StateContext + +internal class StateRouteEntry : StateContext.Element { + override val key = StateRouteEntry + + private var intercepted: Boolean = false + + fun routeIntercepted(): Boolean { + return intercepted + } + + fun interceptRoute() { + if (intercepted) error("State was already intercepted") + intercepted = true + } + + companion object : StateContext.Key +} diff --git a/navigation/src/commonMain/kotlin/ksm/navigation/state/route/plugin/StateRoutePlugin.kt b/navigation/src/commonMain/kotlin/ksm/navigation/route/plugin/StateRoutePlugin.kt similarity index 55% rename from navigation/src/commonMain/kotlin/ksm/navigation/state/route/plugin/StateRoutePlugin.kt rename to navigation/src/commonMain/kotlin/ksm/navigation/route/plugin/StateRoutePlugin.kt index 08881b1..4f34d1e 100644 --- a/navigation/src/commonMain/kotlin/ksm/navigation/state/route/plugin/StateRoutePlugin.kt +++ b/navigation/src/commonMain/kotlin/ksm/navigation/route/plugin/StateRoutePlugin.kt @@ -1,8 +1,9 @@ -package ksm.navigation.state.route.plugin +package ksm.navigation.route.plugin import ksm.annotation.MutateContext import ksm.context.StateContext -import ksm.navigation.state.route.StateRouteScope +import ksm.navigation.route.StateRouteScope +import ksm.navigation.route.routeIntercepted import ksm.plugin.Plugin import ksm.plugin.configuration.interceptor.ConfigurationInterceptor import ksm.plugin.configuration.interceptor.addConfigurationInterceptor @@ -10,35 +11,43 @@ import ksm.plugin.lifecycle.addLifecycleInterceptor import ksm.plugin.lifecycle.interceptor.LifecycleInterceptor public object StateRoutePlugin : Plugin.Singleton { - // todo: вынести в StateRouteStateController - private var block: (StateRouteScope.() -> Unit)? = null @MutateContext override fun install(context: StateContext): StateContext { context.addConfigurationInterceptor(Configuration) - return context + return context + StateRouteStateController() } private object Configuration : ConfigurationInterceptor { @MutateContext override fun onConfigure(context: StateContext): StateContext { context.addLifecycleInterceptor(Lifecycle) - return context + return context + StateRouteEntry() } } private object Lifecycle : LifecycleInterceptor { override fun onCreate(context: StateContext) { - val scope = StateRouteScope(context) - val block = block ?: error("Please call `states` in StateControllerBuilder") - block(scope) - if (!scope.intercepted) { - error("Cannot launch state because there is no handlers for this") + val block = context.require(StateRouteStateController).block() + block(context) + if (!context.routeIntercepted) { + error("Cannot launch state because there is no handlers") } } } - public fun states(block: StateRouteScope.() -> Unit) { - this.block = block + public fun states( + context: StateContext, + block: (StateContext) -> Unit + ) { + context.require(StateRouteStateController).setBlock(block) + } + + public fun routeIntercepted(context: StateContext): Boolean { + return context.require(StateRouteEntry).routeIntercepted() + } + + public fun interceptRoute(context: StateContext) { + context.require(StateRouteEntry).interceptRoute() } } diff --git a/navigation/src/commonMain/kotlin/ksm/navigation/route/plugin/StateRouteStateController.kt b/navigation/src/commonMain/kotlin/ksm/navigation/route/plugin/StateRouteStateController.kt new file mode 100644 index 0000000..f38e37d --- /dev/null +++ b/navigation/src/commonMain/kotlin/ksm/navigation/route/plugin/StateRouteStateController.kt @@ -0,0 +1,19 @@ +package ksm.navigation.route.plugin + +import ksm.context.StateContext + +internal class StateRouteStateController : StateContext.Element { + override val key = StateRouteStateController + + private var block: ((StateContext) -> Unit)? = null + + fun setBlock(block: (StateContext) -> Unit) { + this.block = block + } + + fun block(): (StateContext) -> Unit { + return block ?: error("Please call `states` in StateControllerBuilder") + } + + companion object : StateContext.Key +} diff --git a/navigation/src/commonMain/kotlin/ksm/navigation/state/name/StateRouteScope.kt b/navigation/src/commonMain/kotlin/ksm/navigation/state/name/StateRouteScope.kt index c7e4ce6..546158a 100644 --- a/navigation/src/commonMain/kotlin/ksm/navigation/state/name/StateRouteScope.kt +++ b/navigation/src/commonMain/kotlin/ksm/navigation/state/name/StateRouteScope.kt @@ -1,14 +1,14 @@ package ksm.navigation.state.name -import ksm.navigation.state.route.StateBuilderScope -import ksm.navigation.state.route.StateRouteScope +import ksm.context.StateContext +import ksm.navigation.route.interceptRoute -public inline fun StateRouteScope.named( +public inline fun StateContext.interceptNamedRoute( string: String, - block: StateBuilderScope.() -> Unit + block: () -> Unit ) { - intercept( - predicate = { stateRouteContextForFilter.stateNameOrNull == string }, + interceptRoute( + predicate = { stateNameOrNull == string }, block = block ) } diff --git a/navigation/src/commonMain/kotlin/ksm/navigation/state/route/NavigationController.kt b/navigation/src/commonMain/kotlin/ksm/navigation/state/route/NavigationController.kt deleted file mode 100644 index dfe4b28..0000000 --- a/navigation/src/commonMain/kotlin/ksm/navigation/state/route/NavigationController.kt +++ /dev/null @@ -1,7 +0,0 @@ -package ksm.navigation.state.route - -import ksm.navigation.NavigationController - -public fun NavigationController.states(block: StateRouteScope.() -> Unit) { - context.states(block) -} diff --git a/navigation/src/commonMain/kotlin/ksm/navigation/state/route/StateBuilderScope.kt b/navigation/src/commonMain/kotlin/ksm/navigation/state/route/StateBuilderScope.kt deleted file mode 100644 index c47e98f..0000000 --- a/navigation/src/commonMain/kotlin/ksm/navigation/state/route/StateBuilderScope.kt +++ /dev/null @@ -1,7 +0,0 @@ -package ksm.navigation.state.route - -import ksm.navigation.annotation.StateBuilderDSL -import ksm.context.StateContext - -@StateBuilderDSL -public class StateBuilderScope(public val context: StateContext) diff --git a/navigation/src/commonMain/kotlin/ksm/navigation/state/route/StateContext.kt b/navigation/src/commonMain/kotlin/ksm/navigation/state/route/StateContext.kt deleted file mode 100644 index 9821d79..0000000 --- a/navigation/src/commonMain/kotlin/ksm/navigation/state/route/StateContext.kt +++ /dev/null @@ -1,9 +0,0 @@ -package ksm.navigation.state.route - -import ksm.context.StateContext -import ksm.navigation.state.route.plugin.StateRoutePlugin -import ksm.plugin.plugin - -public fun StateContext.states(block: StateRouteScope.() -> Unit) { - plugin(StateRoutePlugin).states(block) -} diff --git a/navigation/src/commonMain/kotlin/ksm/navigation/state/route/StateRouteScope.kt b/navigation/src/commonMain/kotlin/ksm/navigation/state/route/StateRouteScope.kt deleted file mode 100644 index 6169885..0000000 --- a/navigation/src/commonMain/kotlin/ksm/navigation/state/route/StateRouteScope.kt +++ /dev/null @@ -1,26 +0,0 @@ -package ksm.navigation.state.route - -import ksm.navigation.annotation.StateBuilderDSL -import ksm.context.StateContext - -@StateBuilderDSL -public class StateRouteScope( - public val stateRouteContextForFilter: StateContext -) { - internal var intercepted = false - - public fun intercept() { - require(!intercepted) { "State was already intercepted" } - intercepted = true - } - - public inline fun intercept( - predicate: () -> Boolean, - block: StateBuilderScope.() -> Unit - ) { - if (predicate()) { - intercept() - block(StateBuilderScope(stateRouteContextForFilter)) - } - } -} diff --git a/settings.gradle.kts b/settings.gradle.kts index 5324206..3c19060 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -34,6 +34,7 @@ include( "navigation:navigation-compose", // "navigation:navigation-ktgbotapi", "navigation:navigation-mdi", + "navigation:navigation-react", "navigation:navigation-kotlinx-json", "viewmodel" ) diff --git a/viewmodel/src/commonMain/kotlin/ksm/viewmodel/ViewModelController.kt b/viewmodel/src/commonMain/kotlin/ksm/viewmodel/ViewModelController.kt index 54872ca..07bb5e0 100644 --- a/viewmodel/src/commonMain/kotlin/ksm/viewmodel/ViewModelController.kt +++ b/viewmodel/src/commonMain/kotlin/ksm/viewmodel/ViewModelController.kt @@ -15,7 +15,7 @@ public interface ViewModelController : PluginController { public companion object : StateControllerFactory { override val type: KType = typeOf() - override fun wrap(context: StateContext): PluginController { + override fun wrap(context: StateContext): ViewModelController { return object : ViewModelController { override val context = context } } } @@ -32,13 +32,20 @@ public inline fun viewModelController( ): ViewModelController { val scope = object : ViewModelController.Builder { override var context = context - }.apply { - viewModelRuntime(enableConfiguration, enableLifecycle, enableFinishOnce, enableExceptionHandler) + } + + with(scope) { + viewModelRuntime( + enableConfiguration = enableConfiguration, + enableLifecycle = enableLifecycle, + enableFinishOnce = enableFinishOnce, + enableExceptionHandler = enableExceptionHandler + ) block() } // Calls onConfigure val built = scope.context.createChildContext() - return built.asController() + return ViewModelController.wrap(built) }