<template>
  <div ref="referenceRef" class="sel-reference" @click="popperShow">
    <slot name="reference"></slot>
  </div>
  <teleport v-if="visible" to="body">
    <div v-show="visible" ref="popperRef" class="sel-popper-content">
      <i
        ref="arrowRef"
        :class="placement"
        data-popper-arrow
        class="popper-arrow"
      ></i>
      <slot name="popper"></slot>
    </div>
  </teleport>
</template>

<script lang="ts" setup>
import { ref, unref, nextTick, onUnmounted } from 'vue'
import { createPopper } from '@popperjs/core'
import { onClickOutside } from '@vueuse/core'

const visible = ref(false)
const emits = defineEmits<{
  (e: 'hide'): void
  (e: 'show'): void
}>()
defineOptions({
  name: 'SPopper',
})

interface Props {
  placement: 'top' | 'left' | 'right' | 'bottom'
}

const {
  placement = 'right'
} = defineProps<Props>()
const referenceRef = ref<any>(null)
const popperRef = ref<any>(null)
const arrowRef = ref<any>(null)

let popperInstance: any = null

// 创建 popper 实例
async function createPopperInstance () {
  await nextTick()
  popperInstance = createPopper(unref(referenceRef), unref(popperRef), {
    placement: placement as any,
    modifiers: [
      {
        name: 'arrow',
        options: {
          padding: 5,
          element: unref(arrowRef),
        },
      },
      {
        name: 'offset',
        options: {
          offset: [0, 10]
        }
      }
    ]
  })
  await nextTick()
  popperInstance.update()
  onClickOutside(popperRef, popperHide)
}

// 销毁 popper 实例
function destroyPopperInstance () {
  popperInstance?.destroy?.()
  popperInstance = null
}

onUnmounted(() => {
  destroyPopperInstance()
})

function popperShow () {
  visible.value = true
  createPopperInstance()
  emits('show')
}

function popperHide () {
  visible.value = false
  destroyPopperInstance()
  emits('hide')
}

defineExpose({
  popperShow,
  popperHide
})
</script>

<style lang="scss">
.sel-reference {
  width: 100%;
  height: 100%;
  display: inline-block;
}

.sel-popper-content {
  z-index: 999999;
  position: relative;
  border-radius: 3px;
  box-shadow: 0 0 12px rgba(0, 0, 0, 0.12);
  user-select: none;
  background-color: #fff;

  .popper-arrow {
    border: 6px solid transparent;
    width: 0;
    height: 0;
    position: relative;
    filter: drop-shadow(0px 0px 6px rgba(0, 0, 0, 0.12));

    &.right {
      border-right-color: #fff;
      left: -12px;
    }

    &.bottom {
      border-bottom-color: #fff;
      top: -12px;
    }
  }
}
</style>
