in packages/react-focus/src/components/FocusZone/FocusZone.tsx [1118:1197]
private _moveFocusPaging(isForward: boolean, useDefaultWrap: boolean = true): boolean {
let element = this._activeElement;
if (!element || !this._root.current) {
return false;
}
if (this._isElementInput(element)) {
if (!this._shouldInputLoseFocus(element as HTMLInputElement, isForward)) {
return false;
}
}
const scrollableParent = findScrollableParent(element);
if (!scrollableParent) {
return false;
}
let candidateDistance = -1;
let candidateElement = undefined;
let targetTop = -1;
let targetBottom = -1;
const pagesize = (scrollableParent as HTMLElement).clientHeight;
const activeRect = element.getBoundingClientRect();
do {
element = isForward
? getNextElement(this._root.current, element)
: getPreviousElement(this._root.current, element);
if (element) {
const targetRect = element.getBoundingClientRect();
const targetRectTop = Math.floor(targetRect.top);
const activeRectBottom = Math.floor(activeRect.bottom);
const targetRectBottom = Math.floor(targetRect.bottom);
const activeRectTop = Math.floor(activeRect.top);
const elementDistance = this._getHorizontalDistanceFromCenter(isForward, activeRect, targetRect);
const isElementPassedPageSizeOnPagingDown = isForward && targetRectTop > activeRectBottom + pagesize;
const isElementPassedPageSizeOnPagingUp = !isForward && targetRectBottom < activeRectTop - pagesize;
if (isElementPassedPageSizeOnPagingDown || isElementPassedPageSizeOnPagingUp) {
break;
}
if (elementDistance > -1) {
// for paging down
if (isForward && targetRectTop > targetTop) {
targetTop = targetRectTop;
candidateDistance = elementDistance;
candidateElement = element;
} else if (!isForward && targetRectBottom < targetBottom) {
// for paging up
targetBottom = targetRectBottom;
candidateDistance = elementDistance;
candidateElement = element;
} else if (candidateDistance === -1 || elementDistance <= candidateDistance) {
candidateDistance = elementDistance;
candidateElement = element;
}
}
}
} while (element);
let changedFocus = false;
// Focus the closest candidate
if (candidateElement && candidateElement !== this._activeElement) {
changedFocus = true;
this.focusElement(candidateElement);
this._setFocusAlignment(candidateElement as HTMLElement, false, true);
} else if (this.props.isCircularNavigation && useDefaultWrap) {
if (isForward) {
return this.focusElement(
getNextElement(this._root.current, this._root.current.firstElementChild as HTMLElement, true) as HTMLElement,
);
}
return this.focusElement(
getPreviousElement(
this._root.current,
this._root.current.lastElementChild as HTMLElement,
true,
true,
true,
) as HTMLElement,
);
}
return changedFocus;
}