1
1
import BEM from 'bem.js'
2
2
import { Component } from '../abstract/component'
3
3
4
- /** @type {string } The primary navibation block name. */
4
+ /** @type {string } The primary navigation block name. */
5
5
const BLOCK_PRIMARY_NAVIGATION = 'primary-navigation'
6
6
7
7
/** @type {NodeList<HTMLElement> } The primary navigation block name. */
@@ -10,75 +10,85 @@ const PRIMARY_NAVIGATIONS = BEM.getBEMNodes(BLOCK_PRIMARY_NAVIGATION)
10
10
/** @type {string } The dismissed modifier state, overrides focus/hover. */
11
11
const MODIFIER_DISMISSED = 'dismissed'
12
12
13
+ /** Handler to bypass Safari bug */
14
+ const navigationToggle = document . querySelectorAll (
15
+ '.primary-navigation--toggle'
16
+ )
17
+
13
18
/**
14
19
* Controls the primary navigation and dismissing it using the escape key.
15
20
*/
16
21
class PrimaryNavigation extends Component {
17
22
/**
18
23
* Binds events to callbacks.
19
24
* Callbacks should trigger `setState` which in turn triggers `render`.
25
+ * Focus is split to be handled in Safari
20
26
*/
21
27
bindEvents ( ) {
22
- this . node . addEventListener ( 'focus' , this . onFocus . bind ( this ) )
23
- this . node . addEventListener ( 'mouseenter' , this . onHover . bind ( this ) )
28
+ this . node . addEventListener ( 'click' , this . toggleDesktopNavOpen . bind ( this ) )
29
+ this . node . addEventListener ( 'focusin' , this . onFocusIn . bind ( this ) )
30
+ this . node . addEventListener ( 'focusout' , this . onFocusOut . bind ( this ) )
24
31
window . addEventListener ( 'keyup' , this . onKeyUp . bind ( this ) )
25
32
}
26
33
27
34
/**
28
- * Gets called when `node` receives focus.
35
+ * Gets called when `node` receives focus -in or -out events .
29
36
* Clears the dismissed state, (prevents overriding focus/hover).
37
+ * Focusin and Focusout are used instead of Focus for Safari
30
38
*/
31
- onFocus ( ) {
39
+ onFocusIn ( ) {
32
40
this . setState ( { dismissed : false } )
41
+ this . node . classList . add ( 'primary-navigation--open' )
42
+ }
43
+ onFocusOut ( ) {
44
+ this . setState ( { dismissed : true } )
45
+ this . node . blur ( )
46
+ this . node . classList . remove ( 'primary-navigation--open' )
33
47
}
34
48
35
49
/**
36
- * Gets called when `node` receives focus .
37
- * Clears the dismissed state, (prevents overriding focus/hover ).
50
+ * Gets called when `node` is clicked .
51
+ * Clears the dismissed state, (prevents overriding focus/toggle ).
38
52
*/
39
- onHover ( ) {
53
+ toggleDesktopNavOpen ( event ) {
54
+ event . stopPropagation ( )
40
55
this . setState ( { dismissed : false } )
56
+ this . node . classList . add ( 'primary-navigation--open' )
41
57
}
42
58
43
59
/**
44
60
* Gets called when a key is released.
45
61
* If key is escape key, explicitly dismiss the menu (overriding focus/hover).
46
- * @param {KeyboardEvent } event
62
+ // * @param {KeyboardEvent } event
47
63
*/
48
64
onKeyUp ( event ) {
49
65
if ( event . key === 'Escape' ) {
50
- if ( this . getFocussedChild ( ) || this . getHoveredChild ( ) ) {
51
- this . setState ( { dismissed : true } )
52
- }
66
+ this . setState ( { dismissed : true } )
67
+ this . node . blur ( )
68
+ this . node . classList . remove ( 'primary-navigation--open' )
69
+ // Safari specific
70
+ navigationToggle . forEach ( ( elem ) => {
71
+ elem . blur ( )
72
+ } )
53
73
}
54
74
}
55
75
56
- /**
57
- * Returns the child node in focus (if any).
58
- * @return {HTMLElement|null }
59
- */
60
- getFocussedChild ( ) {
61
- return this . node . querySelector ( ':focus' ) || null
62
- }
63
-
64
- /**
65
- * Returns the hovered child node (if any).
66
- * @return {HTMLElement|null }
67
- */
68
- getHoveredChild ( ) {
69
- return this . node . querySelector ( ':hover' ) || null
70
- }
71
-
72
76
/**
73
77
* Persists state to DOM.
74
78
* Rendering should be one-way traffic and not inspect any current values in DOM.
75
- * @param {Object } state State to render.
79
+ // * @param {Object } state State to render.
76
80
*/
77
81
render ( state ) {
78
82
BEM . toggleModifier ( this . node , MODIFIER_DISMISSED , state . dismissed )
79
83
80
84
if ( state . dismissed ) {
81
- this . getFocussedChild ( ) . blur ( )
85
+ this . node . blur ( )
86
+ // Safari specific
87
+ navigationToggle . forEach ( ( elem ) => {
88
+ elem . blur ( )
89
+ } )
90
+
91
+ return this . node . querySelector ( '.primary-navigation--toggle' )
82
92
}
83
93
}
84
94
}
0 commit comments