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 / organisms / Modal / ModalOrganism / ModalOrganism.tsx
Size: Mime:
import React from 'react'
import { findDOMNode } from 'react-dom'
import ally from '@skava/ally'
import { isObj, isFunction } from 'exotic'
import { observer } from 'xmobx/mobx-react'
import { Overlay } from 'atoms/Overlay'
import { Portal } from 'features/Portal'
import CloseButton from '../CloseButton'
import { Provider, ModalContextProviderProps, Consumer } from '../ModalContext'
import { StyledDialog, ModalTitle, ModalBox } from './styled'
import { Handle, ModalOrganismProps } from './typings'
import { ModalBoxWrap } from './styled'

// const Disabled = ally.maintain.disabled
const Hidden = ally.maintain.hidden
const TabFocus = ally.maintain.tabFocus
const FirstTab = ally.query.firstTabbable
const Key = ally.when.key

/**
 * @see https://christianheilmann.com/2015/08/30/quicky-fading-in-a-newly-created-element-using-css/
 */
@observer
class ModalOrganism extends React.Component<ModalOrganismProps> {
  /**
   * @deprecated
   */
  static get Title() {
    console.warn(
      '@deprecated - do not use Modal.Title - import { ModalTitle } '
    )
    return ModalTitle
  }
  /**
   * @deprecated
   */
  static get CloseButton() {
    console.warn(
      '@deprecated - do not use Modal.CloseButton - import { ModalCloseButton } '
    )
    return CloseButton
  }
  static get Box() {
    console.warn('@deprecated - do not use Modal.Box - import { ModalBox } ')
    return ModalBox
  }
  static get ModalContext() {
    console.warn(
      '@deprecated - do not use Modal.ModalContext - import { Provider } '
    )
    return (props: any) => <Provider {...props} />
  }

  static defaultProps = {
    controller: {},
    isDefaultFocus: true,
  }

  /**
   * @todo why is this still here? just wcag?
   * do not use isHidden
   * @todo @name isVisible
   */
  state = {
    isHidden: true,
  }

  bodyDOM: HTMLElement | null
  dialog: HTMLElement | null
  disabledHandle: Handle
  focusHandle: Handle
  hiddenHandler: Handle
  keyHandler: Handle
  focusedElementBeforeDialogOpened: Element | null

  /* eslint-disable max-statements, react/no-find-dom-node, react/no-did-mount-set-state, react/no-set-state */
  componentDidMount() {
    this.setState({
      isHidden: false,
    })
    this.bodyDOM = document.body
    this.bodyDOM.classList.add('no-scroll')
    this.focusedElementBeforeDialogOpened = document.activeElement

    try {
      const dialogDOM = findDOMNode(this.dialog)
      // this.disabledHandle = Disabled({ filter: dialogDOM })
      this.focusHandle = TabFocus({ context: dialogDOM })
      this.hiddenHandler = Hidden({ filter: '#modal' })
      const element = FirstTab({ context: dialogDOM, defaultToContext: true })
      this.keyHandler = Key({
        escape: (event: KeyboardEvent, disengage: () => void) => {
          event.preventDefault()
          console.debug('pressed escape')
          disengage()
        },
      })
      if (
        isObj(element) &&
        isFunction(element.focus) &&
        this.props.isDefaultFocus
      ) {
        element.focus()
      }
    } catch (allyException) {
      console.error(allyException)
    }
  }

  componentWillUnmount() {
    try {
      this.bodyDOM.classList.remove('no-scroll')
      // this.disabledHandle.disengage()
      this.focusHandle.disengage()
      this.hiddenHandler.disengage()
      this.keyHandler.disengage()

      if (isObj(this.focusedElementBeforeDialogOpened)) {
        this.focusedElementBeforeDialogOpened.focus()
      }
    } catch (allyException) {
      console.error(allyException)
    }
  }

  setRef = dom => {
    this.dialog = dom
  }

  /**
   * @todo probably want <Portal> here for id="modal"...
   */
  renderContext = (context: ModalContextProviderProps) => {
    const allProps = { ...this.props, ...context }
    const {
      className,
      isDefaultFocus,
      controller,
      onClose,
      state,
      children,
      ...remainingProps
    } = allProps

    /**
     * @todo renderOverlay, renderDialog, renderWrap, renderBoxWrap
     * @todo renderBox, renderCloseButton
     * @todo add `nowrap` for Portal...
     *
     * @todo innerRef={this.setRef} < currently using react findDOMNode
     */
    return (
      <Portal id="modal" className={className}>
        <Overlay key="o" isVisible={state!.isVisible} onClick={onClose} />
        <StyledDialog
          open={state!.isVisible}
          isVisible={state!.isVisible}
          className={className}
          {...remainingProps}
        >
          <ModalBoxWrap>{children}</ModalBoxWrap>
        </StyledDialog>
      </Portal>
    )
  }

  render() {
    return <Consumer>{this.renderContext}</Consumer>
  }
}

export { ModalOrganism, ModalOrganism as Modal }
export default ModalOrganism