Skip to content

Extend data-on-intersect #1011

@Mortalife

Description

@Mortalife

Feature Request

I'm hoping that you will consider extending the data-on-intersect attribute to support entry and exit.

Right now, it fires only when you enter the element and there is no way to reuse the the IntersectionObserver to extend it in userland.

I have "solved" this with web components, but I believe it would be beneficial to have inside Datastar for everyone.

Proposed Changes

  • Allow the option to invert the intersection with a modifier, this will allow the user to choose whether they're tracking the entry or exit.
  • Allow the user to omit the callback and receive events instead.
// Icon: mdi-light:vector-intersection
// Slug: Runs an expression on intersection.
// Description: Runs an expression when the element intersects with the viewport.

import type { AttributePlugin, HTMLOrSVG } from '../../engine/types'
import { modifyTiming } from '../../utils/timing'
import { modifyViewTransition } from '../../utils/view-transitions'

const once = new WeakSet<HTMLOrSVG>()

export const OnIntersect: AttributePlugin = {
  type: 'attribute',
  name: 'onIntersect',
  keyReq: 'denied',
  onLoad: ({ el, mods, rx, startBatch, endBatch }) => {
    let callback = () => {
      startBatch()
      rx()
      endBatch()
    }
    callback = modifyTiming(callback, mods)
    callback = modifyViewTransition(callback, mods)
    const options = { threshold: 0 }
    if (mods.has('full')) {
      options.threshold = 1
    } else if (mods.has('half')) {
      options.threshold = 0.5
    }
    let observer: IntersectionObserver | null = new IntersectionObserver(
      (entries) => {
        for (const entry of entries) {
            el.dispatchEvent(
              new CustomEvent(entry.isIntersecting ? "intersect-entry" : "intersect-exit", { bubbles: false })
            )
          
          if (mods.has('exit') ^ entry.isIntersecting) {
            callback()
            if (observer && once.has(el)) {
              observer.disconnect()
            }
          }
        }
      },
      options,
    )
    observer.observe(el)
    if (mods.has('once')) {
      once.add(el)
    }
    return () => {
      if (!mods.has('once')) {
        once.delete(el)
      }
      if (observer) {
        observer.disconnect()
        observer = null
      }
    }
  },
}

Datastar Version

v1.0.0–RC.2

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions