11<template >
2- <div ref =" dropdown" class =" popup-container" tabindex =" -1" :aria-expanded =" dropdownVisible" >
2+ <div
3+ ref =" dropdown"
4+ class =" popup-container"
5+ tabindex =" -1"
6+ :aria-expanded =" dropdownVisible"
7+ :class =" { 'allow-hover': allowHover }"
8+ >
39 <button
410 v-bind =" $attrs"
511 ref =" dropdownButton"
915 >
1016 <slot ></slot >
1117 </button >
18+ <div
19+ v-if =" allowHover"
20+ class =" hover-bounding-box"
21+ :class =" `position-${position}-${direction}`"
22+ ></div >
1223 <div
1324 class =" popup-menu"
1425 :class =" `position-${position}-${direction} ${dropdownVisible ? 'visible' : ''}`"
@@ -34,6 +45,10 @@ const props = defineProps({
3445 type: String ,
3546 default: ' left' ,
3647 },
48+ allowHover: {
49+ type: Boolean ,
50+ default: false ,
51+ },
3752})
3853defineOptions ({
3954 inheritAttrs: false ,
@@ -90,6 +105,133 @@ onBeforeUnmount(() => {
90105.popup-container {
91106 position : relative ;
92107
108+ & .allow-hover .hover-bounding-box {
109+ position : absolute ;
110+ inset : 0 ;
111+ border-radius : var (--radius-md );
112+ z-index : 1 ;
113+
114+ // Debug properties
115+ // background-color: red;
116+ // opacity: 0.1;
117+
118+ // Q: Why is this here and also below?
119+ // A: For the few browsers that do not yet support :has(), this at least
120+ // makes it mostly functional.
121+ & :hover {
122+ & .position-bottom-left ,
123+ & .position-bottom-right {
124+ bottom : -1rem ;
125+ }
126+
127+ & .position-top-left ,
128+ & .position-top-right {
129+ top : -1rem ;
130+ }
131+
132+ & .position-left-up ,
133+ & .position-left-down {
134+ left : -1rem ;
135+ }
136+
137+ & .position-right-up ,
138+ & .position-right-down {
139+ right : -1rem ;
140+ }
141+ }
142+ }
143+
144+ & :not (.allow-hover ) .popup-menu :not (.visible ):not (:focus-within ),
145+ & .allow-hover :not (:has (.hover-bounding-box :hover )):not (:has (.popup-menu :hover ))
146+ .popup-menu :not (.visible ):not (:focus-within ) {
147+ pointer-events : none ;
148+
149+ * ,
150+ ::before ,
151+ ::after {
152+ pointer-events : none ;
153+ }
154+ }
155+
156+ & .allow-hover :has (.hover-bounding-box :hover ),
157+ & .allow-hover :has (.popup-menu :hover ),
158+ :has (.popup-menu.visible ),
159+ :has (.popup-menu :focus-within ) {
160+ :deep (.btn-dropdown-animation svg:last-child ) {
161+ transform : rotate (180deg );
162+ }
163+
164+ .hover-bounding-box {
165+ & .position-bottom-left ,
166+ & .position-bottom-right {
167+ bottom : -1rem ;
168+ }
169+
170+ & .position-top-left ,
171+ & .position-top-right {
172+ top : -1rem ;
173+ }
174+
175+ & .position-left-up ,
176+ & .position-left-down {
177+ left : -1rem ;
178+ }
179+
180+ & .position-right-up ,
181+ & .position-right-down {
182+ right : -1rem ;
183+ }
184+ }
185+ }
186+
187+ & .allow-hover .hover-bounding-box :hover + .popup-menu ,
188+ & .allow-hover .popup-menu :hover ,
189+ .popup-menu.visible ,
190+ .popup-menu :focus-within {
191+ opacity : 1 ;
192+ scale : 1 ;
193+
194+ & .position-bottom-left {
195+ top : calc (100% + var (--gap-sm ));
196+ right : 0 ;
197+ }
198+
199+ & .position-bottom-right {
200+ top : calc (100% + var (--gap-sm ));
201+ left : 0 ;
202+ }
203+
204+ & .position-top-left {
205+ bottom : calc (100% + var (--gap-sm ));
206+ right : 0 ;
207+ }
208+
209+ & .position-top-right {
210+ bottom : calc (100% + var (--gap-sm ));
211+ left : 0 ;
212+ }
213+
214+ & .position-left-up {
215+ bottom : 0rem ;
216+ right : calc (100% + var (--gap-sm ));
217+ }
218+
219+ & .position-left-down {
220+ top : 0rem ;
221+ right : calc (100% + var (--gap-sm ));
222+ }
223+
224+ & .position-right-up {
225+ bottom : 0rem ;
226+ left : calc (100% + var (--gap-sm ));
227+ }
228+
229+ & .position-right-down {
230+ top : 0rem ;
231+ left : calc (100% + var (--gap-sm ));
232+ }
233+ }
234+
93235 .popup-menu {
94236 --_animation-offset : -1rem ;
95237 position : absolute ;
@@ -149,62 +291,6 @@ onBeforeUnmount(() => {
149291 left : calc (100% + var (--gap-sm ) - 1rem );
150292 }
151293
152- & :not (.visible ):not (:focus-within ) {
153- pointer-events : none ;
154-
155- * ,
156- ::before ,
157- ::after {
158- pointer-events : none ;
159- }
160- }
161-
162- & .visible ,
163- & :focus-within {
164- opacity : 1 ;
165- scale : 1 ;
166-
167- & .position-bottom-left {
168- top : calc (100% + var (--gap-sm ));
169- right : 0 ;
170- }
171-
172- & .position-bottom-right {
173- top : calc (100% + var (--gap-sm ));
174- left : 0 ;
175- }
176-
177- & .position-top-left {
178- bottom : calc (100% + var (--gap-sm ));
179- right : 0 ;
180- }
181-
182- & .position-top-right {
183- bottom : calc (100% + var (--gap-sm ));
184- left : 0 ;
185- }
186-
187- & .position-left-up {
188- bottom : 0rem ;
189- right : calc (100% + var (--gap-sm ));
190- }
191-
192- & .position-left-down {
193- top : 0rem ;
194- right : calc (100% + var (--gap-sm ));
195- }
196-
197- & .position-right-up {
198- bottom : 0rem ;
199- left : calc (100% + var (--gap-sm ));
200- }
201-
202- & .position-right-down {
203- top : 0rem ;
204- left : calc (100% + var (--gap-sm ));
205- }
206- }
207-
208294 .btn {
209295 white-space : nowrap ;
210296 }
0 commit comments