# RadioGroup — accessible headless radio group
#
# Exactly one option can be selected. Arrow keys move focus and selection.
# Ships zero CSS.
#
# Usage:
#   RadioGroup value <=> size
#     div $value: "sm", "Small"
#     div $value: "md", "Medium"
#     div $value: "lg", "Large"

export RadioGroup = component
  @value:: any := null
  @disabled:: boolean := false
  @orientation:: "horizontal" | "vertical" := "vertical"
  @name:: string := ""

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

  _select: (val) ->
    return if @disabled
    @value = val
    @emit 'change', @value

  onKeydown: (e) ->
    radios = @_root?.querySelectorAll('[role="radio"]')
    return unless radios?.length
    focused = Array.from(radios).indexOf(document.activeElement)
    return if focused < 0
    len = radios.length
    move = (idx) => radios[idx]?.focus(); @_select(_options[idx]?.dataset.value)
    ARIA.rovingNav e, {
      next:  => move((focused + 1) %% len)
      prev:  => move((focused - 1) %% len)
      first: => move(0)
      last:  => move(len - 1)
    }, 'both'

  render
    div ref: "_root", role: "radiogroup", aria-orientation: @orientation
      $orientation: @orientation
      $disabled: @disabled?!

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

      for opt, idx in _options
        button role: "radio"
          tabindex: (if (opt.dataset.value is @value) or (@value is null and idx is 0) then "0" else "-1")
          aria-checked: opt.dataset.value is @value
          $checked: (opt.dataset.value is @value)?!
          $disabled: @disabled?!
          $value: opt.dataset.value
          @click: (=> @_select(opt.dataset.value))
          = opt.textContent
