iterative/vscode-dvc

View on GitHub
webview/src/shared/components/contextMenu/ContextMenu.tsx

Summary

Maintainability
A
0 mins
Test Coverage
A
95%
import React from 'react'
import { Instance } from 'tippy.js'
import Tooltip from '../tooltip/Tooltip'

const positionContextMenuAndDisableEvents = (
  instance: Instance,
  event: PointerEvent
) => {
  event.preventDefault()
  instance.setProps({
    getReferenceClientRect() {
      const { top, bottom, height } = instance.reference.getBoundingClientRect()
      return {
        bottom,
        height,
        left: event.clientX,
        right: event.clientX,
        top,
        width: 0
      } as DOMRect
    }
  })

  const handleDefaultEvent = (event: Event) => {
    event.preventDefault()
  }

  instance.reference.removeEventListener('contextmenu', handleDefaultEvent)
  instance.reference.addEventListener('contextmenu', handleDefaultEvent)

  const hideOnClick = (event: Event) => {
    if (
      event.target instanceof HTMLElement &&
      !event.target.closest('[aria-disabled=true]')
    ) {
      !instance.state.isDestroyed && instance.hide()
    }
  }

  instance.popper.removeEventListener('click', hideOnClick)
  instance.popper.addEventListener('click', hideOnClick)

  window.addEventListener('click', hideOnClick, { once: true })
}

export interface ContextMenuProps {
  children: React.ReactElement
  content?: React.ReactNode
  disabled?: boolean
  onShow?: () => void
  onHide?: () => void
  trigger?: string
}

export const ContextMenu: React.FC<ContextMenuProps> = ({
  children,
  content,
  disabled,
  onShow,
  onHide,
  trigger = 'contextmenu'
}) => (
  <Tooltip
    trigger={trigger}
    delay={[100, 200]}
    placement="bottom-start"
    interactive
    isContextMenu={true}
    onTrigger={positionContextMenuAndDisableEvents}
    onClickOutside={(instance: Instance) => instance.hide()}
    hideOnClick={false}
    content={content}
    onShow={onShow}
    onHide={onHide}
    disabled={!content || disabled}
    appendTo="parent"
    followCursor="initial"
    offset={[0, 0]}
  >
    {children}
  </Tooltip>
)