1
1
import { Controller } from "@hotwired/stimulus" ;
2
- import { computePosition , flip , shift , offset } from "@floating-ui/dom" ;
2
+ import {
3
+ computePosition ,
4
+ flip ,
5
+ shift ,
6
+ offset ,
7
+ autoUpdate ,
8
+ } from "@floating-ui/dom" ;
3
9
4
10
export default class extends Controller {
5
11
static targets = [ "trigger" , "content" , "menuItem" ] ;
@@ -12,17 +18,34 @@ export default class extends Controller {
12
18
type : Object ,
13
19
default : { } ,
14
20
} ,
15
- }
21
+ } ;
16
22
17
23
connect ( ) {
18
24
this . boundHandleKeydown = this . #handleKeydown. bind ( this ) ; // Bind the function so we can remove it later
19
25
this . selectedIndex = - 1 ;
26
+
27
+ this . #setupAutoUpdate( ) ;
28
+ }
29
+
30
+ disconnect ( ) {
31
+ if ( this . autoUpdateCleanup ) {
32
+ this . autoUpdateCleanup ( ) ;
33
+ }
34
+ }
35
+
36
+ #setupAutoUpdate( ) {
37
+ this . autoUpdateCleanup = autoUpdate (
38
+ this . triggerTarget ,
39
+ this . contentTarget ,
40
+ this . #computeTooltip. bind ( this ) ,
41
+ ) ;
20
42
}
21
43
22
44
#computeTooltip( ) {
23
45
computePosition ( this . triggerTarget , this . contentTarget , {
24
46
placement : this . optionsValue . placement || "top" ,
25
47
middleware : [ flip ( ) , shift ( ) , offset ( 8 ) ] ,
48
+ strategy : this . optionsValue . strategy || "absolute" ,
26
49
} ) . then ( ( { x, y } ) => {
27
50
Object . assign ( this . contentTarget . style , {
28
51
left : `${ x } px` ,
@@ -40,14 +63,16 @@ export default class extends Controller {
40
63
}
41
64
42
65
toggle ( ) {
43
- this . contentTarget . classList . contains ( "hidden" ) ? this . #open( ) : this . close ( ) ;
66
+ this . contentTarget . classList . contains ( "hidden" )
67
+ ? this . #open( )
68
+ : this . close ( ) ;
44
69
}
45
70
46
71
#open( ) {
47
72
this . openValue = true ;
48
73
this . #deselectAll( ) ;
49
74
this . #addEventListeners( ) ;
50
- this . #computeTooltip( )
75
+ this . #computeTooltip( ) ;
51
76
this . contentTarget . classList . remove ( "hidden" ) ;
52
77
}
53
78
@@ -59,15 +84,17 @@ export default class extends Controller {
59
84
60
85
#handleKeydown( e ) {
61
86
// return if no menu items (one line fix for)
62
- if ( this . menuItemTargets . length === 0 ) { return ; }
87
+ if ( this . menuItemTargets . length === 0 ) {
88
+ return ;
89
+ }
63
90
64
- if ( e . key === ' ArrowDown' ) {
91
+ if ( e . key === " ArrowDown" ) {
65
92
e . preventDefault ( ) ;
66
93
this . #updateSelectedItem( 1 ) ;
67
- } else if ( e . key === ' ArrowUp' ) {
94
+ } else if ( e . key === " ArrowUp" ) {
68
95
e . preventDefault ( ) ;
69
96
this . #updateSelectedItem( - 1 ) ;
70
- } else if ( e . key === ' Enter' && this . selectedIndex !== - 1 ) {
97
+ } else if ( e . key === " Enter" && this . selectedIndex !== - 1 ) {
71
98
e . preventDefault ( ) ;
72
99
this . menuItemTargets [ this . selectedIndex ] . click ( ) ;
73
100
}
@@ -76,7 +103,7 @@ export default class extends Controller {
76
103
#updateSelectedItem( direction ) {
77
104
// Check if any of the menuItemTargets have aria-selected="true" and set the selectedIndex to that index
78
105
this . menuItemTargets . forEach ( ( item , index ) => {
79
- if ( item . getAttribute ( ' aria-selected' ) === ' true' ) {
106
+ if ( item . getAttribute ( " aria-selected" ) === " true" ) {
80
107
this . selectedIndex = index ;
81
108
}
82
109
} ) ;
@@ -99,22 +126,24 @@ export default class extends Controller {
99
126
#toggleAriaSelected( element , isSelected ) {
100
127
// Add or remove attribute
101
128
if ( isSelected ) {
102
- element . setAttribute ( ' aria-selected' , ' true' ) ;
129
+ element . setAttribute ( " aria-selected" , " true" ) ;
103
130
} else {
104
- element . removeAttribute ( ' aria-selected' ) ;
131
+ element . removeAttribute ( " aria-selected" ) ;
105
132
}
106
133
}
107
134
108
135
#deselectAll( ) {
109
- this . menuItemTargets . forEach ( item => this . #toggleAriaSelected( item , false ) ) ;
136
+ this . menuItemTargets . forEach ( ( item ) =>
137
+ this . #toggleAriaSelected( item , false ) ,
138
+ ) ;
110
139
this . selectedIndex = - 1 ;
111
140
}
112
141
113
142
#addEventListeners( ) {
114
- document . addEventListener ( ' keydown' , this . boundHandleKeydown ) ;
143
+ document . addEventListener ( " keydown" , this . boundHandleKeydown ) ;
115
144
}
116
145
117
146
#removeEventListeners( ) {
118
- document . removeEventListener ( ' keydown' , this . boundHandleKeydown ) ;
147
+ document . removeEventListener ( " keydown" , this . boundHandleKeydown ) ;
119
148
}
120
149
}
0 commit comments