diff --git a/showcase/src/wasmJsMain/kotlin/dev/kindling/showcase/docs/Site.kt b/showcase/src/wasmJsMain/kotlin/dev/kindling/showcase/docs/Site.kt index bcba025..feeadc6 100644 --- a/showcase/src/wasmJsMain/kotlin/dev/kindling/showcase/docs/Site.kt +++ b/showcase/src/wasmJsMain/kotlin/dev/kindling/showcase/docs/Site.kt @@ -229,12 +229,12 @@ private fun PageContent(page: DocPage?, loc: Loc, dark: Boolean, flat: List 0 && scroll.value >= scroll.maxValue - 4 var active = headings.firstOrNull()?.first for ((index, _) in headings) { - val c = coords[index]?.takeIf { it.isAttached } ?: continue - if (c.positionInRoot().y - top <= 110f) active = index else break + val y = coords[index].safeY() ?: continue + if (y - top <= 110f) active = index else break } if (atEnd) headings.lastOrNull()?.first ?: active else active } @@ -242,8 +242,10 @@ private fun PageContent(page: DocPage?, loc: Loc, dark: Boolean, flat: List Unit = { index -> val target = coords[index] val top = viewport - if (target != null && target.isAttached && top != null) { - val y = target.positionInRoot().y - top.positionInRoot().y + val ty = target.safeY() + val vy = top.safeY() + if (ty != null && vy != null) { + val y = ty - vy scope.launch { scroll.animateScrollTo((scroll.value + y - 24f).toInt().coerceAtLeast(0)) } } } @@ -381,3 +383,7 @@ private fun SearchOverlay(pages: List, onClose: () -> Unit, onPick: (St } } } + +/** Position in the root, or null when the layout is detached (it can be removed between the check and the read). */ +private fun LayoutCoordinates?.safeY(): Float? = + if (this == null || !isAttached) null else try { positionInRoot().y } catch (_: IllegalArgumentException) { null }