<template>
  <div
    class="inline-block relative hoverme"
    ref="containerEl"
    @mouseover="mouseover"
    @mouseout="mouseout"
  >
    <slot></slot>
    <component :is="teleport ? Teleport : 'div'" to="body">
      <div
        class="messageBox"
        ref="box"
        :style="{
          left: left + marginLeft + 'px',
          top: top + marginTop + 'px',
        }"
        @mouseover="boxMouseOver"
        @mouseout="boxMouseOut"
      >
        <slot name="message"> </slot>
      </div>
    </component>
  </div>
</template>

<script setup lang="ts">
import {
  ref,
  watch,
  Teleport as teleport_,
  TeleportProps,
  VNodeProps,
  onMounted,
} from "vue";
const box = ref<HTMLDivElement>();

withDefaults(
  defineProps<{
    teleport?: boolean;
    marginLeft?: number;
    marginTop?: number;
  }>(),
  {
    teleport: true,
    marginLeft: 0,
    marginTop: 0,
  }
);

onMounted(() => {});

const containerEl = ref<HTMLDivElement>();
const left = ref(0);
const top = ref(0);

const Teleport = teleport_ as {
  new (): {
    $props: VNodeProps & TeleportProps;
  };
};

const t = "all .3s ease-out";

const hover = ref(false);
const boxHover = ref(false);

const finalHover = ref(false);

const emit = defineEmits(["over", "out"]);

watch(
  () => [hover.value, boxHover.value],
  () => {
    if (hover.value || boxHover.value) {
      finalHover.value = true;
    } else if (!hover.value && !boxHover.value) {
      finalHover.value = false;
    }
  }
);

watch(finalHover, () => {
  if (finalHover.value) {
    const rect = containerEl.value?.getBoundingClientRect();
    left.value = rect?.left!;
    top.value = rect?.top!;
    if (!box.value) return;
    emit("over");
    box.value.style.transition = "none";
    box.value.style.transition = t;
    box.value.style.display = "block";
    box.value.style.opacity = "0";
    setTimeout(() => {
      box.value!.style.opacity = "1";
    });
  } else {
    if (!box.value) return;
    emit("out");
    box.value.style.opacity = "0";
    box.value.ontransitionend = () => {
      if (box.value!.style.opacity === "0") box.value!.style.display = "none";
    };
  }
});

const mouseover = () => {
  hover.value = true;
};

const mouseout = () => {
  hover.value = false;
};

const boxMouseOver = () => {
  boxHover.value = true;
};

const boxMouseOut = () => {
  boxHover.value = false;
};
</script>

<style lang="scss">
/* 
in  block -> opacity 1
out opacity 0 -> none
 */
.hoverme {
}
.messageBox {
  display: none;
  z-index: 100;
  position: fixed;
  padding: 19px 18px;
  width: 308px;
  background: #f7f7f7;
  box-shadow: 0px 2px 10px 0px rgba(200, 200, 200, 0.5);
  border-radius: var(--border-radius);
  border: 1px solid #e7e7e7;

  font-size: 12px;
  font-family: PingFangSC-Regular, PingFang SC;
  font-weight: 400;
  color: #717171;
  line-height: 22px;
}
</style>
