diff --git a/CHANGELOG.md b/CHANGELOG.md index c57ce273f2d..3d8a8572ac1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ ## 0.9.16 +* `Common`: + * New extension `Node#onRemoved` + * `Compose`: + * New extension `Composition#linkWithRoot` for removing of composition with root element +* `Coroutines`: + * `Compose`: + * New function `renderComposableAndLinkToContextAndRoot` with linking of composition to root element + ## 0.9.15 * `FSM`: diff --git a/common/compose/src/jsMain/kotlin/dev/inmo/micro_utils/common/compose/AttachCompositionToElementRemoving.kt b/common/compose/src/jsMain/kotlin/dev/inmo/micro_utils/common/compose/AttachCompositionToElementRemoving.kt new file mode 100644 index 00000000000..a476c4c9aa3 --- /dev/null +++ b/common/compose/src/jsMain/kotlin/dev/inmo/micro_utils/common/compose/AttachCompositionToElementRemoving.kt @@ -0,0 +1,9 @@ +package dev.inmo.micro_utils.common.compose + +import androidx.compose.runtime.Composition +import dev.inmo.micro_utils.common.onRemoved +import org.w3c.dom.Element + +fun Composition.linkWithElement(element: Element) { + element.onRemoved { dispose() } +} diff --git a/common/src/jsMain/kotlin/dev/inmo/micro_utils/common/HTMLElementDomChanged.kt b/common/src/jsMain/kotlin/dev/inmo/micro_utils/common/HTMLElementDomChanged.kt new file mode 100644 index 00000000000..5d803dca1fb --- /dev/null +++ b/common/src/jsMain/kotlin/dev/inmo/micro_utils/common/HTMLElementDomChanged.kt @@ -0,0 +1,21 @@ +package dev.inmo.micro_utils.common + +import kotlinx.browser.document +import org.w3c.dom.* + +fun Node.onRemoved(block: () -> Unit) { + lateinit var observer: MutationObserver + + observer = MutationObserver { _, _ -> + fun checkIfRemoved(node: Node): Boolean { + return node.parentNode != document && (node.parentNode ?.let { checkIfRemoved(it) } ?: true) + } + + if (checkIfRemoved(this)) { + observer.disconnect() + block() + } + } + + observer.observe(document, MutationObserverInit(childList = true, subtree = true)) +} diff --git a/coroutines/compose/build.gradle b/coroutines/compose/build.gradle index c71171b88f3..7405e30efa0 100644 --- a/coroutines/compose/build.gradle +++ b/coroutines/compose/build.gradle @@ -13,6 +13,7 @@ kotlin { dependencies { api libs.kt.coroutines api project(":micro_utils.coroutines") + api project(":micro_utils.common.compose") } } } diff --git a/coroutines/compose/src/jsMain/kotlin/dev/inmo/micro_utils/coroutines/compose/RenderComposableWithLinkToContext.kt b/coroutines/compose/src/jsMain/kotlin/dev/inmo/micro_utils/coroutines/compose/RenderComposableWithLinkToContext.kt index 85d78e4011b..f78ae088f76 100644 --- a/coroutines/compose/src/jsMain/kotlin/dev/inmo/micro_utils/coroutines/compose/RenderComposableWithLinkToContext.kt +++ b/coroutines/compose/src/jsMain/kotlin/dev/inmo/micro_utils/coroutines/compose/RenderComposableWithLinkToContext.kt @@ -1,6 +1,7 @@ package dev.inmo.micro_utils.coroutines.compose import androidx.compose.runtime.* +import dev.inmo.micro_utils.common.compose.linkWithElement import kotlinx.coroutines.* import org.jetbrains.compose.web.dom.DOMScope import org.w3c.dom.Element @@ -14,3 +15,12 @@ suspend fun renderComposableAndLinkToContext( currentCoroutineContext() ) } + +suspend fun renderComposableAndLinkToContextAndRoot( + root: TElement, + monotonicFrameClock: MonotonicFrameClock = DefaultMonotonicFrameClock, + content: @Composable DOMScope.() -> Unit +): Composition = org.jetbrains.compose.web.renderComposable(root, monotonicFrameClock, content).apply { + linkWithContext(currentCoroutineContext()) + linkWithElement(root) +}