tooltip.ts 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. import type { Directive, DirectiveBinding } from 'vue'
  2. import tippy, { type Instance, type Placement } from 'tippy.js'
  3. import './tooltip.scss'
  4. const TOOLTIP_INSTANCE = 'TOOLTIP_INSTANCE'
  5. interface CustomHTMLElement extends HTMLElement {
  6. [TOOLTIP_INSTANCE]?: Instance
  7. }
  8. type Delay = number | [number | null, number | null]
  9. interface BindingValue {
  10. content: string
  11. placement?: Placement
  12. delay?: Delay
  13. }
  14. const TooltipDirective: Directive = {
  15. mounted(el: CustomHTMLElement, binding: DirectiveBinding<BindingValue | string>) {
  16. let content = ''
  17. let placement: Placement = 'top'
  18. let delay: Delay = [300, 0]
  19. if (typeof binding.value === 'string') {
  20. content = binding.value
  21. }
  22. else {
  23. content = binding.value.content
  24. if (binding.value.placement !== undefined) placement = binding.value.placement
  25. if (binding.value.delay !== undefined) delay = binding.value.delay
  26. }
  27. el[TOOLTIP_INSTANCE] = tippy(el, {
  28. content,
  29. theme: 'tooltip',
  30. duration: 100,
  31. animation: 'scale',
  32. allowHTML: true,
  33. placement,
  34. delay,
  35. })
  36. },
  37. updated(el: CustomHTMLElement, binding: DirectiveBinding<BindingValue | string>) {
  38. let content = ''
  39. if (typeof binding.value === 'string') {
  40. content = binding.value
  41. }
  42. else {
  43. content = binding.value.content
  44. }
  45. if (el[TOOLTIP_INSTANCE]) el[TOOLTIP_INSTANCE].setContent(content)
  46. },
  47. unmounted(el: CustomHTMLElement) {
  48. if (el[TOOLTIP_INSTANCE]) el[TOOLTIP_INSTANCE].destroy()
  49. },
  50. }
  51. export default TooltipDirective