41
41
// .floating-content[data-theme~="warning"] { ... }
42
42
43
43
import { ref , watch , computed , toRefs } from " vue" ;
44
+ import type { Ref } from " vue" ;
44
45
import { useElementHover } from " @vueuse/core" ;
45
46
import * as floating from " @floating-ui/vue" ;
46
- import type { Placement } from " @floating-ui/vue" ;
47
+ import type { Placement , VirtualElement } from " @floating-ui/vue" ;
47
48
48
49
// interface ----
49
50
50
51
type OnShowFn = () => void ;
51
52
type OnHideFn = () => void ;
52
53
53
54
type Props = {
55
+ target? : HTMLElement | VirtualElement ;
54
56
placement? : Placement ;
55
57
interactive? : boolean ;
58
+ inline? : boolean ;
56
59
delay? : number | [number , number ];
57
60
arrow? : boolean ;
58
61
theme? : string ;
@@ -61,8 +64,10 @@ type Props = {
61
64
onHide? : OnHideFn ;
62
65
};
63
66
const props = withDefaults (defineProps <Props >(), {
67
+ target: undefined ,
64
68
placement: " top" ,
65
69
interactive: false ,
70
+ inline: false ,
66
71
delay: 0 ,
67
72
arrow: true ,
68
73
theme: " light" ,
@@ -73,15 +78,20 @@ const slots = defineSlots();
73
78
// define varibales ----
74
79
75
80
const {
81
+ target : targetProp,
76
82
placement : placementProp,
77
83
interactive,
84
+ inline,
78
85
delay,
79
86
arrow : arrowProp,
80
87
theme : themeProp,
81
- trigger : triggerRef ,
88
+ trigger : triggerProp ,
82
89
} = toRefs (props );
83
90
84
- const targetRef = ref ();
91
+ const defaultSlotRef = ref ();
92
+ const targetRef = computed ((): HTMLElement | VirtualElement =>
93
+ targetProp .value ?? defaultSlotRef .value
94
+ ); // targetRef変数を消せるかも?HMRで動作する?
85
95
const floatingRef = ref ();
86
96
const arrowRef = ref ();
87
97
@@ -96,6 +106,7 @@ const {
96
106
whileElementsMounted: floating .autoUpdate ,
97
107
placement: placementProp ,
98
108
middleware: [
109
+ ... (inline .value ? [floating .inline ()] : []),
99
110
floating .offset (6 ),
100
111
floating .flip ({ fallbackAxisSideDirection: " end" , crossAxis: false }),
101
112
floating .shift ({ padding: 5 }),
@@ -110,19 +121,24 @@ const delayOptions = computed(() => {
110
121
return { delayEnter , delayLeave };
111
122
});
112
123
113
- // define hover states ----
114
-
115
- const isTargetHovered = useElementHover (targetRef , {
116
- delayEnter: delayOptions .value .delayEnter ,
117
- delayLeave: delayOptions .value .delayLeave + (interactive .value ? 100 : 0 ),
124
+ const isUsingDefaultSlot = computed ((): boolean => {
125
+ return ! targetProp .value ;
118
126
});
127
+
128
+ // define trigger states ----
129
+
130
+ const triggerRef = triggerProp .value !== undefined ?
131
+ triggerProp as Ref <boolean > :
132
+ useElementHover (defaultSlotRef , {
133
+ delayEnter: delayOptions .value .delayEnter ,
134
+ delayLeave: delayOptions .value .delayLeave + (interactive .value ? 100 : 0 ),
135
+ });
119
136
const isTooltipHovered = useElementHover (floatingRef , {
120
137
delayEnter: 0 , // keep tooltip open when hovering over the tooltip
121
138
delayLeave: delayOptions .value .delayLeave ,
122
139
});
123
140
const isTriggered = computed ((): boolean => {
124
- const triggered = triggerRef .value ?? isTargetHovered .value ;
125
- const t = triggered || (interactive .value && isTooltipHovered .value );
141
+ const t = triggerRef .value || (interactive .value && isTooltipHovered .value );
126
142
return t ;
127
143
});
128
144
@@ -155,7 +171,7 @@ const arrowStyles = computed(() => {
155
171
</script >
156
172
157
173
<template >
158
- <span ref =" targetRef " >
174
+ <span v-if = " isUsingDefaultSlot " ref =" defaultSlotRef " >
159
175
<slot />
160
176
</span >
161
177
<Teleport v-if =" slots.content" to =" body" >
0 commit comments