private _moveFocusPaging()

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;
  }