@@ -6,7 +6,7 @@ import { overEvery, find, findLast, reverse, first, last } from 'lodash';
6
6
/**
7
7
* WordPress dependencies
8
8
*/
9
- import { Component , createRef , useEffect } from '@wordpress/element' ;
9
+ import { Component , createRef } from '@wordpress/element' ;
10
10
import {
11
11
computeCaretRect ,
12
12
focus ,
@@ -18,7 +18,7 @@ import {
18
18
isEntirelySelected ,
19
19
} from '@wordpress/dom' ;
20
20
import { UP , DOWN , LEFT , RIGHT , TAB , isKeyboardEvent } from '@wordpress/keycodes' ;
21
- import { withSelect , withDispatch , useDispatch } from '@wordpress/data' ;
21
+ import { withSelect , withDispatch , useSelect , useDispatch } from '@wordpress/data' ;
22
22
import { compose } from '@wordpress/compose' ;
23
23
24
24
/**
@@ -77,9 +77,30 @@ export function isNavigationCandidate( element, keyCode, hasModifier ) {
77
77
* Renders focus capturing areas to redirect focus to the selected block if not
78
78
* in Navigation mode.
79
79
*/
80
- function FocusCapture ( { isReverse, clientId, isNavigationMode } ) {
80
+ function FocusCapture ( { selectedClientId, isReverse, containerRef } ) {
81
+ const isNavigationMode = useSelect ( ( select ) =>
82
+ select ( 'core/block-editor' ) . isNavigationMode ( )
83
+ ) ;
84
+ const { setNavigationMode } = useDispatch ( 'core/block-editor' ) ;
85
+
81
86
function onFocus ( ) {
82
- const wrapper = getBlockFocusableWrapper ( clientId ) ;
87
+ if ( ! selectedClientId ) {
88
+ setNavigationMode ( true ) ;
89
+
90
+ const tabbables = focus . tabbable . find ( containerRef . current ) ;
91
+
92
+ if ( tabbables . length ) {
93
+ if ( isReverse ) {
94
+ last ( tabbables ) . focus ( ) ;
95
+ } else {
96
+ first ( tabbables ) . focus ( ) ;
97
+ }
98
+ }
99
+
100
+ return ;
101
+ }
102
+
103
+ const wrapper = getBlockFocusableWrapper ( selectedClientId ) ;
83
104
84
105
if ( isReverse ) {
85
106
const tabbables = focus . tabbable . find ( wrapper ) ;
@@ -91,7 +112,7 @@ function FocusCapture( { isReverse, clientId, isNavigationMode } ) {
91
112
92
113
return (
93
114
< div
94
- tabIndex = { clientId && ! isNavigationMode ? '0' : undefined }
115
+ tabIndex = { ! isNavigationMode ? '0' : undefined }
95
116
onFocus = { onFocus }
96
117
// Needs to be positioned within the viewport, so focus to this
97
118
// element does not scroll the page.
@@ -100,33 +121,11 @@ function FocusCapture( { isReverse, clientId, isNavigationMode } ) {
100
121
) ;
101
122
}
102
123
103
- /**
104
- * Enables navigation mode as soon as tab is pressed.
105
- * Meant to be rendered if there is no block selected.
106
- */
107
- function EnableNavigationModeOnTab ( ) {
108
- const { setNavigationMode } = useDispatch ( 'core/block-editor' ) ;
109
- useEffect ( ( ) => {
110
- function handleTab ( event ) {
111
- if ( event . keyCode === TAB ) {
112
- setNavigationMode ( true ) ;
113
- }
114
- }
115
-
116
- window . addEventListener ( 'keydown' , handleTab ) ;
117
- return ( ) => {
118
- window . removeEventListener ( 'keydown' , handleTab ) ;
119
- } ;
120
- } , [ setNavigationMode ] ) ;
121
- return null ;
122
- }
123
-
124
124
class WritingFlow extends Component {
125
125
constructor ( ) {
126
126
super ( ...arguments ) ;
127
127
128
128
this . onKeyDown = this . onKeyDown . bind ( this ) ;
129
- this . bindContainer = this . bindContainer . bind ( this ) ;
130
129
this . onMouseDown = this . onMouseDown . bind ( this ) ;
131
130
this . focusLastTextField = this . focusLastTextField . bind ( this ) ;
132
131
@@ -139,6 +138,8 @@ class WritingFlow extends Component {
139
138
*/
140
139
this . verticalRect = null ;
141
140
141
+ this . container = createRef ( ) ;
142
+
142
143
/**
143
144
* Reference of the writing flow appender element.
144
145
* The reference is used to focus the first tabbable element after the block list
@@ -147,10 +148,6 @@ class WritingFlow extends Component {
147
148
this . appender = createRef ( ) ;
148
149
}
149
150
150
- bindContainer ( ref ) {
151
- this . container = ref ;
152
- }
153
-
154
151
onMouseDown ( ) {
155
152
this . verticalRect = null ;
156
153
}
@@ -168,7 +165,7 @@ class WritingFlow extends Component {
168
165
getClosestTabbable ( target , isReverse ) {
169
166
// Since the current focus target is not guaranteed to be a text field,
170
167
// find all focusables. Tabbability is considered later.
171
- let focusableNodes = focus . focusable . find ( this . container ) ;
168
+ let focusableNodes = focus . focusable . find ( this . container . current ) ;
172
169
173
170
if ( isReverse ) {
174
171
focusableNodes = reverse ( focusableNodes ) ;
@@ -336,7 +333,7 @@ class WritingFlow extends Component {
336
333
337
334
if ( isShift ) {
338
335
if ( target === wrapper ) {
339
- const focusableParent = this . container . closest ( '[tabindex]' ) ;
336
+ const focusableParent = this . container . current . closest ( '[tabindex]' ) ;
340
337
const beforeEditorElement = focus . tabbable . findPrevious ( focusableParent ) ;
341
338
beforeEditorElement . focus ( ) ;
342
339
event . preventDefault ( ) ;
@@ -346,7 +343,7 @@ class WritingFlow extends Component {
346
343
const tabbables = focus . tabbable . find ( wrapper ) ;
347
344
348
345
if ( target === last ( tabbables ) ) {
349
- const focusableParent = this . container . closest ( '[tabindex]' ) ;
346
+ const focusableParent = this . container . current . closest ( '[tabindex]' ) ;
350
347
const afterEditorElement = focus . tabbable . findNext ( focusableParent ) ;
351
348
afterEditorElement . focus ( ) ;
352
349
event . preventDefault ( ) ;
@@ -452,7 +449,7 @@ class WritingFlow extends Component {
452
449
* Sets focus to the end of the last tabbable text field, if one exists.
453
450
*/
454
451
focusLastTextField ( ) {
455
- const focusableNodes = focus . focusable . find ( this . container ) ;
452
+ const focusableNodes = focus . focusable . find ( this . container . current ) ;
456
453
const target = findLast ( focusableNodes , isTabbableTextField ) ;
457
454
if ( target ) {
458
455
placeCaretAtHorizontalEdge ( target , true ) ;
@@ -462,41 +459,39 @@ class WritingFlow extends Component {
462
459
render ( ) {
463
460
const {
464
461
children,
465
- isNavigationMode,
466
462
selectedBlockClientId,
467
463
selectionStartClientId,
468
464
} = this . props ;
469
- const clientId = selectedBlockClientId || selectionStartClientId ;
465
+ const selectedClientId = selectedBlockClientId || selectionStartClientId ;
470
466
471
467
// Disable reason: Wrapper itself is non-interactive, but must capture
472
468
// bubbling events from children to determine focus transition intents.
473
469
/* eslint-disable jsx-a11y/no-static-element-interactions */
474
470
return (
475
471
< div className = "block-editor-writing-flow" >
472
+ < FocusCapture
473
+ selectedClientId = { selectedClientId }
474
+ containerRef = { this . container }
475
+ />
476
476
< div
477
- ref = { this . bindContainer }
477
+ ref = { this . container }
478
478
onKeyDown = { this . onKeyDown }
479
479
onMouseDown = { this . onMouseDown }
480
480
>
481
- < FocusCapture
482
- clientId = { clientId }
483
- isNavigationMode = { isNavigationMode }
484
- />
485
481
{ children }
486
- < FocusCapture
487
- clientId = { clientId }
488
- isNavigationMode = { isNavigationMode }
489
- isReverse
490
- />
491
482
</ div >
483
+ < FocusCapture
484
+ selectedClientId = { selectedClientId }
485
+ containerRef = { this . container }
486
+ isReverse
487
+ />
492
488
< div
493
489
ref = { this . appender }
494
490
aria-hidden
495
491
tabIndex = { - 1 }
496
492
onClick = { this . focusLastTextField }
497
493
className = "block-editor-writing-flow__click-redirect"
498
494
/>
499
- { ! clientId && < EnableNavigationModeOnTab /> }
500
495
</ div >
501
496
) ;
502
497
/* eslint-enable jsx-a11y/no-static-element-interactions */
0 commit comments