varabyte / kobweb

A modern framework for full stack web apps in Kotlin, built upon Compose HTML
https://kobweb.varabyte.com
Apache License 2.0
1.53k stars 68 forks source link

Add support for visibility tracking for elements #223

Open bitspittle opened 1 year ago

bitspittle commented 1 year ago

It might be nice for Kobweb to provide an easy way to report if an element in visible on screen or not.

One user said this was possible with React:

<TrackVisibility>
  {({ isVisible }) =>
    <div className={isVisible ? "animate__animated animate__zoomIn" : ""}>
      <img src={headerImg} alt="Header Img"/>
    </div>}
</TrackVisibility>

Also, Stevdza-san implemented this: https://github.com/stevdza-san/LandingPageCompose/blob/master/site/src/jsMain/kotlin/com/stevdza/san/util/Functions.kt


One possible API is to use a syntax similar to what we currently use for popups, imagine something like this:

var boxIsOnScreen by remember { mutableStateOf(false) }
Box(Modifier.thenIf(boxIsOnScreen, ...)) {
   ...
}
VisibilityTracker(ElementTarget.PreviousSibling) { boxIsOnScreen = it }

Or (I'm not 100% sure this can work) we can follow the react syntax, something like:

VisibilityTracker { isVisible ->
   Box(Modifier.thenIf(isVisible)) {
}

which loses some flexbility compared to the element target version, but it's nice because you don't need to do all the remember boilerplate. Maybe we can even offer APIs for both approaches.


(Also, there may be other APIs like this worth adding, like tracking if an element has focus, or whatever else. There may be a more general API to pull out of here, something like a RefTracker concept that VisibilityTracker can build on top of, like

RefTracker(map = { ref -> isOnScreen(ref) }, { isVisible -> ... })
bitspittle commented 1 year ago

Note: Marked this with 1.1 because it shouldn't block a 1.0 release, but solving this in the 1.0 timeframe might still be a killer feature for users.

bitspittle commented 1 year ago

Note from another user:

Would be great for kobweb to have the isinviewport functionality, based on the intersectionobserver api instead probably

Also you asked earlier about the IntersectionObserver API, there are kotlin wrappers for it: https://github.com/JetBrains/kotlin-wrappers/blob/master/kotlin-browser/src/jsMain/generated/web/dom/observers/IntersectionObserver.kt GitHub