Add "skip to content", "skip to navigation" links (#38006)
This commit is contained in:
1 parent
87004ddb96
commit
816e63d2a5
10 files changed
+281
-43
No files matched your search
@@ -1,3 +1,8 @@
|
||||
import {
|
||||
getColumnSkipLinkId,
|
||||
getNavigationSkipLinkId,
|
||||
} from '../components/skip_links';
|
||||
|
||||
/**
|
||||
* Out of a list of elements, return the first one whose top edge
|
||||
* is inside of the viewport, and return the element and its BoundingClientRect.
|
||||
@@ -20,9 +25,29 @@ function findFirstVisibleWithRect(
|
||||
return null;
|
||||
}
|
||||
|
||||
function focusColumnTitle(index: number, multiColumn: boolean) {
|
||||
if (multiColumn) {
|
||||
const column = document.querySelector(`.column:nth-child(${index})`);
|
||||
if (column) {
|
||||
column
|
||||
.querySelector<HTMLAnchorElement>(
|
||||
`#${getColumnSkipLinkId(index - 1)}, #${getNavigationSkipLinkId()}`,
|
||||
)
|
||||
?.focus();
|
||||
}
|
||||
} else {
|
||||
const idSelector =
|
||||
index === 2
|
||||
? `#${getNavigationSkipLinkId()}`
|
||||
: `#${getColumnSkipLinkId(1)}`;
|
||||
|
||||
document.querySelector<HTMLAnchorElement>(idSelector)?.focus();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move focus to the column of the passed index (1-based).
|
||||
* Focus is placed on the topmost visible item
|
||||
* Focus is placed on the topmost visible item, or the column title
|
||||
*/
|
||||
export function focusColumn(index = 1) {
|
||||
// Skip the leftmost drawer in multi-column mode
|
||||
@@ -35,11 +60,21 @@ export function focusColumn(index = 1) {
|
||||
`.column:nth-child(${index + indexOffset})`,
|
||||
);
|
||||
|
||||
if (!column) return;
|
||||
function fallback() {
|
||||
focusColumnTitle(index + indexOffset, isMultiColumnLayout);
|
||||
}
|
||||
|
||||
if (!column) {
|
||||
fallback();
|
||||
return;
|
||||
}
|
||||
|
||||
const container = column.querySelector('.scrollable');
|
||||
|
||||
if (!container) return;
|
||||
if (!container) {
|
||||
fallback();
|
||||
return;
|
||||
}
|
||||
|
||||
const focusableItems = Array.from(
|
||||
container.querySelectorAll<HTMLElement>(
|
||||
@@ -50,20 +85,23 @@ export function focusColumn(index = 1) {
|
||||
// Find first item visible in the viewport
|
||||
const itemToFocus = findFirstVisibleWithRect(focusableItems);
|
||||
|
||||
if (itemToFocus) {
|
||||
const viewportWidth =
|
||||
window.innerWidth || document.documentElement.clientWidth;
|
||||
const { item, rect } = itemToFocus;
|
||||
|
||||
if (
|
||||
container.scrollTop > item.offsetTop ||
|
||||
rect.right > viewportWidth ||
|
||||
rect.left < 0
|
||||
) {
|
||||
itemToFocus.item.scrollIntoView(true);
|
||||
}
|
||||
itemToFocus.item.focus();
|
||||
if (!itemToFocus) {
|
||||
fallback();
|
||||
return;
|
||||
}
|
||||
|
||||
const viewportWidth =
|
||||
window.innerWidth || document.documentElement.clientWidth;
|
||||
const { item, rect } = itemToFocus;
|
||||
|
||||
if (
|
||||
container.scrollTop > item.offsetTop ||
|
||||
rect.right > viewportWidth ||
|
||||
rect.left < 0
|
||||
) {
|
||||
itemToFocus.item.scrollIntoView(true);
|
||||
}
|
||||
itemToFocus.item.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user