# ContextMenu — accessible headless right-click menu
#
# Opens on contextmenu event (right-click) over the trigger area.
# Keyboard navigation matches Menu. Ships zero CSS.
#
# Usage:
#   ContextMenu @select: handleAction
#     div $trigger: true
#       p "Right-click this area"
#     div $item: "cut", "Cut"
#     div $item: "copy", "Copy"
#     div $item: "paste", "Paste"

export ContextMenu = component
  @disabled := false

  open := false
  highlightedIndex := -1
  posX := 0
  posY := 0

  _menuItems ~=
    return [] unless @_slot
    Array.from(@_slot.querySelectorAll('[data-item]') or [])

  _triggerEl ~=
    return null unless @_slot
    @_slot.querySelector('[data-trigger]')

  _onContextMenu: (e) ->
    return if @disabled
    e.preventDefault()
    posX = e.clientX
    posY = e.clientY
    open = true
    highlightedIndex = 0
    requestAnimationFrame =>
      @_list?.querySelectorAll('[role="menuitem"]')[0]?.focus()

  close: ->
    open = false
    highlightedIndex = -1

  selectIndex: (idx) ->
    item = _menuItems[idx]
    return unless item
    return if item.dataset.disabled?
    @emit 'select', item.dataset.item
    @close()

  _onKeydown: (e) ->
    len = _menuItems.length
    return unless len
    switch e.key
      when 'ArrowDown'
        e.preventDefault()
        highlightedIndex = (highlightedIndex + 1) %% len
        @_list?.querySelectorAll('[role="menuitem"]')[highlightedIndex]?.focus()
      when 'ArrowUp'
        e.preventDefault()
        highlightedIndex = (highlightedIndex - 1) %% len
        @_list?.querySelectorAll('[role="menuitem"]')[highlightedIndex]?.focus()
      when 'Home'
        e.preventDefault()
        highlightedIndex = 0
        @_list?.querySelectorAll('[role="menuitem"]')[0]?.focus()
      when 'End'
        e.preventDefault()
        highlightedIndex = len - 1
        @_list?.querySelectorAll('[role="menuitem"]')[len - 1]?.focus()
      when 'Enter', ' '
        e.preventDefault()
        @selectIndex(highlightedIndex)
      when 'Escape', 'Tab'
        e.preventDefault() if e.key is 'Escape'
        @close()

  ~>
    if open
      onDown = (e) =>
        unless @_list?.contains(e.target)
          @close()
      document.addEventListener 'mousedown', onDown
      return -> document.removeEventListener 'mousedown', onDown

  render
    . @contextmenu: @_onContextMenu

      . ref: "_slot", style: "display:none"
        slot

      if _triggerEl
        . innerHTML: _triggerEl.innerHTML

      if open
        div ref: "_list", role: "menu", $open: true, @keydown: @_onKeydown
          style: "position:fixed;left:#{posX}px;top:#{posY}px;z-index:50"
          for item, idx in _menuItems
            div role: "menuitem", tabindex: "-1"
              $highlighted: (idx is highlightedIndex)?!
              $disabled: item.dataset.disabled?!
              $value: item.dataset.item
              @click: (=> @selectIndex(idx))
              @mouseenter: (=> highlightedIndex = idx)
              = item.textContent
