Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
@skava/react-dom-observable / src / intersection / IntersectionObserver.tsx
Size: Mime:
import * as React from 'react'
import { findDOMNode } from 'react-dom'
import { createObserver, observeElement, unobserveElement } from './observer'
import { isDOMTypeElement, shallowCompare } from './utils'
import { IntersectionObserverProps } from './typings'

const observerOptions = ['root', 'rootMargin', 'threshold']
const observerProps = ['disabled'].concat(observerOptions)
const objectProto = Object.prototype

class IntersectionObserverComponent extends React.Component<IntersectionObserverProps> {
  static displayName = 'IntersectionObserver'

  get options() {
    return observerOptions.reduce((options, key) => {
      // tslint:disable:align
      if (objectProto.hasOwnProperty.call(this.props, key)) {
        const useQuery =
          key === 'root' &&
          objectProto.toString.call(this.props[key]) === '[object String]'

        options[key] = useQuery
          ? document.querySelector(this.props[key])
          : this.props[key]
      }
      return options
    }, {})
  }

  handleChange = (event: React.ChangeEvent<any> | IntersectionObserverEntry) => {
    this.props.onChange(event, this.unobserve)

    if (this.props.onlyOnce) {
      // eslint-disable-next-line no-undef
      if (process.env.NODE_ENV !== 'production') {
        if ('isIntersecting' in event) {
          console.error(
            `deprecation: onlyOnce requires isIntersecting to exists in IntersectionObserverEntry's prototype. Either your browser or your polyfill lacks support.`
          )
        }
      }

      if ((event as any).isIntersecting) {
        this.unobserve()
      }
    }
    // eslint-disable-next-line no-undef
    if (process.env.NODE_ENV !== 'production') {
      console.warn(
        !this.props.hasOwnProperty('onlyOnce'),
        'ReactIntersectionObserver: [deprecation] Use the second argument of onChange to unobserve a target instead of onlyOnce. This prop will be removed in the next major version.'
      )
    }
  }

  target: Element
  renderedTarget: Element
  targetChanged: boolean
  observer: IntersectionObserver

  /**
   * @todo forwardRef........ !!!
   */
  handleNode = (target: HTMLElement) => {
    /**
     * Forward hijacked ref to user.
     */
    const nodeRef = (this.props.children as any).ref

    if (nodeRef) {
      if (typeof nodeRef === 'function') {
        nodeRef(target)
      } else if (typeof nodeRef === 'object') {
        nodeRef.current = target
      }
    }

    /**
     * This is a bit ugly: would like to use getSnapshotBeforeUpdate(), but we do not want to depend on
     * react-lifecycles-compat to support React versions prior to 16.3 as this extra boolean gets the job done.
     */
    this.targetChanged =
      (this.renderedTarget && target) != null && this.renderedTarget !== target

    if (this.targetChanged) {
      this.unobserve()
    }

    this.target = target
  }

  observe = () => {
    this.target = (
      isDOMTypeElement(this.target)
        ? this.target
        : findDOMNode(this.target)
    ) as HTMLElement

    this.observer = createObserver(this.options)
    observeElement(this)
  }

  unobserve = () => {
    if (this.target != null) {
      unobserveElement(this)
    }
  }

  componentDidMount() {
    if (!this.props.disabled) {
      this.observe()
    }
  }

  componentDidUpdate(prevProps: {[key: string]: unknown}) {
    const propsChanged = observerProps.some(prop =>
      shallowCompare(this.props[prop], prevProps[prop])
    )

    if (propsChanged) {
      this.unobserve()
    }

    if (this.targetChanged || propsChanged) {
      if (!this.props.disabled) {
        this.observe()
      }
    }
  }

  componentWillUnmount() {
    this.unobserve()
  }

  render() {
    // this value is null on the first render
    this.renderedTarget = this.target

    // @todo, not React.Children.Only?
    return React.cloneElement(React.Children.only(this.props.children), {
      ref: this.handleNode,
    })
  }
}

export { IntersectionObserverComponent }
export default IntersectionObserverComponent