<template>
  <div class="relative">
    <div ref="triggerRef">
      <slot />
    </div>
    <Teleport
      v-if="teleport"
      to="body"
    >
      <Transition
        enter-active-class="transition duration-100 ease-out"
        enter-from-class="opacity-0 scale-95"
        enter-to-class="opacity-100 scale-100"
        leave-active-class="transition duration-75 ease-in"
        leave-from-class="opacity-100 scale-100"
        leave-to-class="opacity-0 scale-95"
      >
        <div
          v-if="open && placement"
          ref="menuRef"
          role="menu"
          class="fixed z-[100] min-w-[6rem] rounded border border-kestrel-border bg-kestrel-surface py-1 shadow-glow shadow-glow-dropdown"
          :style="menuStyle"
        >
          <slot name="menu" />
        </div>
      </Transition>
    </Teleport>
    <Transition
      v-else
      name="dropdown"
    >
      <div
        v-if="open"
        ref="menuRef"
        role="menu"
        class="absolute right-0 top-full z-[2001] mt-1 min-w-[160px] rounded border border-kestrel-border bg-kestrel-surface py-1 shadow-glow"
      >
        <slot name="menu" />
      </div>
    </Transition>
  </div>
</template>

<script setup>
import { ref, computed, watch, nextTick, onMounted, onBeforeUnmount } from 'vue'

const props = defineProps({
  open: { type: Boolean, default: false },
  teleport: { type: Boolean, default: false },
})

const emit = defineEmits(['close'])

const triggerRef = ref(null)
const menuRef = ref(null)
const placement = ref(null)
const menuStyle = computed(() => {
  if (!placement.value) return undefined
  const p = placement.value
  return { top: p.top + 'px', left: p.left + 'px', minWidth: p.minWidth + 'px' }
})

watch(() => props.open, (open) => {
  if (open && triggerRef.value && props.teleport) {
    nextTick(() => {
      const rect = triggerRef.value.getBoundingClientRect()
      placement.value = {
        top: rect.bottom + 4,
        left: rect.left,
        minWidth: Math.max(rect.width, 96),
      }
    })
  }
  else {
    placement.value = null
  }
})

function onDocumentClick(e) {
  if (!props.open) return
  const trigger = triggerRef.value
  const menu = menuRef.value
  const inTrigger = trigger && trigger.contains(e.target)
  const inMenu = menu && menu.contains(e.target)
  if (!inTrigger && !inMenu) emit('close')
}

onMounted(() => {
  document.addEventListener('click', onDocumentClick)
})
onBeforeUnmount(() => {
  document.removeEventListener('click', onDocumentClick)
})
</script>
