bufferapp/ui

View on GitHub
src/components/DropdownMenu/DropdownMenu.tsx

Summary

Maintainability
B
6 hrs
Test Coverage
B
80%
/* eslint-disable jsx-a11y/role-supports-aria-props */
import React from 'react'
import PropTypes from 'prop-types'
import { DropdownItems, Item } from './style'
import PopupMenu from './PopupMenu/PopupMenu'
import { keyCode } from './keyCode'

export default class DropdownMenu extends React.Component {
  // @ts-expect-error TS(7006) FIXME: Parameter 'props' implicitly has an 'any' type.
  constructor(props) {
    super(props)

    this.state = {
      isOpen: false,
      usingMouse: false,
    }

    // @ts-expect-error TS(2339) FIXME: Property 'keyCode' does not exist on type 'Dropdow... Remove this comment to see the full error message
    this.keyCode = keyCode

    this.handleKeydown = this.handleKeydown.bind(this)
    this.handlePopupBlur = this.handlePopupBlur.bind(this)
    this.handleMousedown = this.handleMousedown.bind(this)
  }

  componentDidMount() {
    // @ts-expect-error TS(2339) FIXME: Property 'itemsNode' does not exist on type 'Dropd... Remove this comment to see the full error message
    this.itemsNode.addEventListener('keydown', this.handleKeydown)
    // @ts-expect-error TS(2339) FIXME: Property 'itemsNode' does not exist on type 'Dropd... Remove this comment to see the full error message
    this.itemsNode.addEventListener('mousedown', this.handleMousedown)
  }

  componentWillUnmount() {
    // @ts-expect-error TS(2339) FIXME: Property 'itemsNode' does not exist on type 'Dropd... Remove this comment to see the full error message
    this.itemsNode.removeEventListener('keydown', this.handleKeydown)
    // @ts-expect-error TS(2339) FIXME: Property 'itemsNode' does not exist on type 'Dropd... Remove this comment to see the full error message
    this.itemsNode.removeEventListener('mousedown', this.handleMousedown)
  }

  handleMousedown = () => {
    this.setState({ usingMouse: true })
  }

  togglePopup = () => {
    // @ts-expect-error TS(2339) FIXME: Property 'isOpen' does not exist on type 'Readonly... Remove this comment to see the full error message
    const { isOpen } = this.state
    this.setState({ isOpen: !isOpen })
  }

  // @ts-expect-error TS(2339) FIXME: Property 'isOpen' does not exist on type 'Readonly... Remove this comment to see the full error message
  isPopupOpen = () => this.state.isOpen

  openPopup = () => {
    this.setState({ isOpen: true })
  }

  closePopup = () => {
    this.setState({ isOpen: false })
  }

  // @ts-expect-error TS(7006) FIXME: Parameter 'event' implicitly has an 'any' type.
  handleKeydown = (event) => {
    let flag = false
    switch (event.keyCode) {
      // @ts-expect-error TS(2339) FIXME: Property 'keyCode' does not exist on type 'Dropdow... Remove this comment to see the full error message
      case this.keyCode.SPACE:
      // @ts-expect-error TS(2339) FIXME: Property 'keyCode' does not exist on type 'Dropdow... Remove this comment to see the full error message
      case this.keyCode.RETURN:
      // @ts-expect-error TS(2339) FIXME: Property 'keyCode' does not exist on type 'Dropdow... Remove this comment to see the full error message
      case this.keyCode.DOWN:
        if (!this.isPopupOpen()) {
          this.openPopup()
          flag = true
        }
        break
      // @ts-expect-error TS(2339) FIXME: Property 'keyCode' does not exist on type 'Dropdow... Remove this comment to see the full error message
      case this.keyCode.ESC:
      // @ts-expect-error TS(2339) FIXME: Property 'keyCode' does not exist on type 'Dropdow... Remove this comment to see the full error message
      case this.keyCode.TAB:
        this.closePopup()
        break
      default:
        break
    }

    this.setState({ usingMouse: false })

    if (flag) {
      event.stopPropagation()
      event.preventDefault()
    }
  }

  // @ts-expect-error TS(7006) FIXME: Parameter 'event' implicitly has an 'any' type.
  handlePopupBlur = (event) => {
    const outsideOfPopup = !event.currentTarget.contains(event.relatedTarget)
    setTimeout(() => {
      if (this.isPopupOpen() && outsideOfPopup) {
        this.closePopup()
      }
    }, 300)
  }

  render() {
    const {
      // @ts-expect-error TS(2339) FIXME: Property 'menubarItem' does not exist on type 'Rea... Remove this comment to see the full error message
      menubarItem,
      // @ts-expect-error TS(2339) FIXME: Property 'items' does not exist on type 'Readonly<... Remove this comment to see the full error message
      items,
      // @ts-expect-error TS(2339) FIXME: Property 'ariaLabel' does not exist on type 'Reado... Remove this comment to see the full error message
      ariaLabel,
      // @ts-expect-error TS(2339) FIXME: Property 'ariaLabelPopup' does not exist on type '... Remove this comment to see the full error message
      ariaLabelPopup,
      // @ts-expect-error TS(2339) FIXME: Property 'horizontalOffset' does not exist on type... Remove this comment to see the full error message
      horizontalOffset,
      // @ts-expect-error TS(2339) FIXME: Property 'xPosition' does not exist on type 'Reado... Remove this comment to see the full error message
      xPosition,
      // @ts-expect-error TS(2339) FIXME: Property 'onOpen' does not exist on type 'Readonly... Remove this comment to see the full error message
      onOpen,
    } = this.props

    const MenubarItem = React.cloneElement(menubarItem)

    return (
      <DropdownItems
        // @ts-expect-error TS(2339) FIXME: Property 'itemsNode' does not exist on type 'Dropd... Remove this comment to see the full error message
        ref={(itemsNode) => (this.itemsNode = itemsNode)}
        role="menubar"
        aria-label={ariaLabel}
        // @ts-expect-error TS(2769) FIXME: No overload matches this call.
        usingMouse={this.state.usingMouse}
      >
        {/* @ts-expect-error TS(2769) FIXME: No overload matches this call. */}
        <Item role="none" menuOption>
          <MenubarItem.type
            {...MenubarItem.props}
            role="menuitem"
            // @ts-expect-error TS(2322) FIXME: Type 'string' is not assignable to type 'number'.
            tabIndex="0"
            aria-haspopup="true"
            // @ts-expect-error TS(2339) FIXME: Property 'isOpen' does not exist on type 'Readonly... Remove this comment to see the full error message
            aria-expanded={this.state.isOpen}
            onKeyDown={(ev) => this.handleKeydown(ev)}
            onClick={(ev) => {
              this.togglePopup()
              ev.preventDefault()
            }}
          />
          <PopupMenu
            // @ts-expect-error TS(2322) FIXME: Type '{ role: string; xPosition: any; items: any; ... Remove this comment to see the full error message
            role="menu"
            xPosition={xPosition}
            items={items}
            aria-label={ariaLabelPopup}
            horizontalOffset={horizontalOffset}
            // @ts-expect-error TS(2339) FIXME: Property 'isOpen' does not exist on type 'Readonly... Remove this comment to see the full error message
            isOpen={this.state.isOpen}
            // @ts-expect-error TS(2339) FIXME: Property 'usingMouse' does not exist on type 'Read... Remove this comment to see the full error message
            usingMouse={this.state.usingMouse}
            closePopup={this.closePopup}
            // @ts-expect-error TS(7006) FIXME: Parameter 'event' implicitly has an 'any' type.
            onBlur={(event) => this.handlePopupBlur(event)}
            onOpen={onOpen}
          />
        </Item>
      </DropdownItems>
    )
  }
}

// @ts-expect-error TS(2339) FIXME: Property 'propTypes' does not exist on type 'typeo... Remove this comment to see the full error message
DropdownMenu.propTypes = {
  /** Link in the NavBar that triggers the popup */
  menubarItem: PropTypes.node.isRequired,

  /** Aria label for list component */
  ariaLabel: PropTypes.string.isRequired,

  /** Aria label for popup menu, it should preferibly be the same as the menubarItem name */
  ariaLabelPopup: PropTypes.string,

  /** xPosition for Dropdown menu */
  xPosition: PropTypes.string,

  /** Items list to display in the popup menu */
  items: PropTypes.arrayOf(
    PropTypes.shape({
      id: PropTypes.string,
      title: PropTypes.string,
      colors: PropTypes.shape({
        title: PropTypes.string,
        iconHover: PropTypes.string,
      }),
    }),
  ).isRequired,

  /** onOpen function to fire when the Dropdown menu is open */
  onOpen: PropTypes.func,
}

// @ts-expect-error TS(2339) FIXME: Property 'defaultProps' does not exist on type 'ty... Remove this comment to see the full error message
DropdownMenu.defaultProps = {
  ariaLabelPopup: null,
  xPosition: 'right',
  onOpen: null,
}