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/ui / src / components / features / Portal / Portal.tsx
Size: Mime:
import React from 'react'
import toClassName from 'classnames'
import { createPortal } from 'react-dom'
import { isObj, isUndefined, isString } from 'exotic'
import {
  removeElement,
  getElementOrCreate,
  appendToBodyIfRequired,
} from './deps'
import { PortalProps } from './typings'

/**
 * @api https://reactjs.org/docs/portals.html
 */
class Portal extends React.PureComponent<PortalProps> {
  isComponentMounted = false
  defaultNode: HTMLElement | undefined

  componentWillUnmount() {
    this.isComponentMounted = false

    if (isObj(this.defaultNode) && isObj(this.defaultNode.classList)) {
      this.defaultNode.classList.remove('visible')
      if (isString(this.props.id) === false) {
        removeElement(this.defaultNode)
        this.defaultNode = undefined
      }
    }
  }

  /**
   * @see https://reactjs.org/docs/reconciliation.html
   */
  componentDidMount() {
    this.isComponentMounted = true
    this.forceUpdate()
  }

  /**
   * @deprecated
   * @todo remove this, we can access using props...
   */
  get className() {
    return toClassName('portal', this.props.className, {
      visible: this.props.isVisible,
      hidden: this.props.isVisible === false,
    })
  }

  /**
   * @todo reduce reading & writing from the DOM here, bad @@perf
   */
  render() {
    /**
     * for best rendering, should not render on server
     */
    if (this.isComponentMounted === false) {
      return null
    }

    // if we send an id, find it
    if (isString(this.props.id)) {
      this.defaultNode = getElementOrCreate(this.props.id)
      this.defaultNode.className = this.className
      this.defaultNode.setAttribute(
        'aria-hidden',
        String(!this.props.isVisible)
      )
    }
    // otherwise, we could send a dom node
    else if (!this.props.node && isUndefined(this.defaultNode)) {
      this.defaultNode = document.createElement('div')
    }

    // if we had to create it, we need to append it
    appendToBodyIfRequired(this.defaultNode!)

    return createPortal(
      this.props.children,
      this.props.node || this.defaultNode
    )
  }
}

export { Portal }
export default Portal