-
Notifications
You must be signed in to change notification settings - Fork 287
/
Copy pathuse-popover.ts
106 lines (97 loc) · 3.14 KB
/
use-popover.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import { toRefs, ref, computed, watch, onUnmounted, onMounted } from 'vue';
import type { Ref, ComputedRef } from 'vue';
import { debounce } from 'lodash';
import { PopoverProps, UsePopoverEvent } from './popover-types';
const TransformOriginMap: Record<string, string> = {
top: '50% calc(100% + 8px)',
bottom: '50% -8px',
left: 'calc(100% + 8px)',
right: '-8px 50%',
};
export function usePopover(
props: PopoverProps,
visible: Ref<boolean>,
placement: Ref<string>,
origin: Ref<HTMLElement | undefined>,
popoverRef: Ref
): { overlayStyles: ComputedRef<Record<string, number | string>> } {
const { trigger, isOpen } = toRefs(props);
const overlayStyles = computed(() => ({
zIndex: 'var(--devui-z-index-pop-up, 1060)',
transformOrigin: TransformOriginMap[placement.value],
}));
const onDocumentClick: (e: Event) => void = (e: Event) => {
if (!origin.value?.contains(<HTMLElement>e.target) && !popoverRef.value.$el?.contains(e.target)) {
visible.value = false;
}
};
watch(isOpen, (isOpenVal) => {
visible.value = isOpenVal;
});
watch(visible, () => {
if (visible.value && trigger.value !== 'manually') {
document.addEventListener('click', onDocumentClick);
} else {
document.removeEventListener('click', onDocumentClick);
}
});
onUnmounted(() => {
document.removeEventListener('click', onDocumentClick);
});
return { overlayStyles };
}
export function usePopoverEvent(props: PopoverProps, visible: Ref<boolean>, origin: Ref): UsePopoverEvent {
const { trigger, position, mouseEnterDelay, mouseLeaveDelay, disabled } = toRefs(props);
const isClick: ComputedRef<boolean> = computed(() => trigger.value === 'click');
const isHover: ComputedRef<boolean> = computed(() => trigger.value === 'hover');
const placement: Ref<string> = ref(position.value[0].split('-')[0]);
const isEnter: Ref<boolean> = ref(false);
const onClick = () => {
if (disabled.value) {
return;
}
isClick.value && (visible.value = !visible.value);
};
const enter = debounce(() => {
isEnter.value && (visible.value = true);
}, mouseEnterDelay.value);
const leave = debounce(() => {
!isEnter.value && (visible.value = false);
}, mouseLeaveDelay.value);
const onMouseenter = () => {
if (disabled.value) {
return;
}
if (!isHover.value) {
isEnter.value = true;
enter();
}
};
const onMouseleave = () => {
if (!isHover.value) {
isEnter.value = false;
leave();
}
};
const quickLeave = () => {
isEnter.value = false;
visible.value = false;
};
watch(disabled, (newVal) => {
if (newVal && visible.value) {
quickLeave();
}
});
const handlePositionChange: (pos: string) => void = (pos: string) => {
placement.value = pos.split('-')[0];
};
onMounted(() => {
if (trigger.value === 'click') {
origin.value?.addEventListener('click', onClick);
} else if (trigger.value === 'hover') {
origin.value?.addEventListener('mouseenter', onMouseenter);
origin.value?.addEventListener('mouseleave', onMouseleave);
}
});
return { placement, handlePositionChange, onMouseenter, onMouseleave };
}