Skip to content

Commit

Permalink
Safari: see if compositing layer size is more reasonable when positio…
Browse files Browse the repository at this point in the history
…n fixed divs are not inserted into content (#32824)

* Safari: remove position:fixed div in scrollable content so compositing layers are of more reasonable size

* Prevent scroll after focusing focus capture element

* Prevent scrolling when tabbing back to a focus capture div

Co-authored-by: Ella van Durpe <ella@vandurpe.com>
  • Loading branch information
2 people authored and youknowriad committed Jul 13, 2021
1 parent aab428c commit f13f2ed
Showing 1 changed file with 47 additions and 9 deletions.
56 changes: 47 additions & 9 deletions packages/block-editor/src/components/writing-flow/use-tab-nav.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,6 @@ import { useRef } from '@wordpress/element';
*/
import { store as blockEditorStore } from '../../store';

/**
* Useful for positioning an element within the viewport so focussing the
* element does not scroll the page.
*/
const PREVENT_SCROLL_ON_FOCUS = { position: 'fixed' };

function isFormElement( element ) {
const { tagName } = element;
return (
Expand Down Expand Up @@ -75,7 +69,6 @@ export default function useTabNav() {
ref={ focusCaptureBeforeRef }
tabIndex={ focusCaptureTabIndex }
onFocus={ onFocusCapture }
style={ PREVENT_SCROLL_ON_FOCUS }
/>
);

Expand All @@ -84,7 +77,6 @@ export default function useTabNav() {
ref={ focusCaptureAfterRef }
tabIndex={ focusCaptureTabIndex }
onFocus={ onFocusCapture }
style={ PREVENT_SCROLL_ON_FOCUS }
/>
);

Expand Down Expand Up @@ -131,16 +123,62 @@ export default function useTabNav() {
// doesn't refocus this block and so it allows default behaviour
// (moving focus to the next tabbable element).
noCapture.current = true;
next.current.focus();

// Focusing the focus capture element, which is located above and
// below the editor, should not scroll the page all the way up or
// down.
next.current.focus( { preventScroll: true } );
}

function onFocusOut( event ) {
lastFocus.current = event.target;
}

// When tabbing back to an element in block list, this event handler prevents scrolling if the
// focus capture divs (before/after) are outside of the viewport. (For example shift+tab back to a paragraph
// when focus is on a sidebar element. This prevents the scrollable writing area from jumping either to the
// top or bottom of the document.
//
// Note that it isn't possible to disable scrolling in the onFocus event. We need to intercept this
// earlier in the keypress handler, and call focus( { preventScroll: true } ) instead.
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLOrForeignElement/focus#parameters
function preventScrollOnTab( event ) {
if ( event.keyCode !== TAB ) {
return;
}

if ( event.target?.getAttribute( 'role' ) === 'region' ) {
return;
}

if ( container.current === event.target ) {
return;
}

const isShift = event.shiftKey;
const direction = isShift ? 'findPrevious' : 'findNext';
const target = focus.tabbable[ direction ]( event.target );
// only do something when the next tabbable is a focus capture div (before/after)
if (
target === focusCaptureBeforeRef.current ||
target === focusCaptureAfterRef.current
) {
event.preventDefault();
target.focus( { preventScroll: true } );
}
}

node.ownerDocument.defaultView.addEventListener(
'keydown',
preventScrollOnTab
);
node.addEventListener( 'keydown', onKeyDown );
node.addEventListener( 'focusout', onFocusOut );
return () => {
node.ownerDocument.defaultView.removeEventListener(
'keydown',
preventScrollOnTab
);
node.removeEventListener( 'keydown', onKeyDown );
node.removeEventListener( 'focusout', onFocusOut );
};
Expand Down

0 comments on commit f13f2ed

Please sign in to comment.