Skip to content

Commit

Permalink
Always use getDocument in FocusZone and FocusTrapZone (#10187)
Browse files Browse the repository at this point in the history
* Use getDocument instead document in FocusZone and FocusTrapZone

* Change files

* improvements after CR comments

* FTZ improvement

* return document for SSR case

* check document for SSR case
  • Loading branch information
sophieH29 authored and JasonGore committed Aug 20, 2019
1 parent b7824ed commit 5c6b118
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"type": "patch",
"comment": "Use getDocument instead document in FocusZone and FocusTrapZone",
"packageName": "office-ui-fabric-react",
"email": "sohuts@microsoft.com",
"commit": "c4766bf28c3c6fe6021e2a0f277524bcc64064b4",
"date": "2019-08-19T15:03:13.879Z"
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
getFirstTabbable,
getLastTabbable,
getNextElement,
getDocument,
focusAsync,
initializeComponentRef,
on
Expand Down Expand Up @@ -67,7 +68,7 @@ export class FocusTrapZone extends React.Component<IFocusTrapZoneProps, {}> impl
if (
!this.props.disabled ||
this.props.forceFocusInsideTrap ||
!elementContains(this._root.current, document.activeElement as HTMLElement)
!elementContains(this._root.current, this._getDocument().activeElement as HTMLElement)
) {
this._returnFocusToInitiator();
}
Expand Down Expand Up @@ -162,7 +163,7 @@ export class FocusTrapZone extends React.Component<IFocusTrapZoneProps, {}> impl
// even when it's not. Using document.activeElement is another way
// for us to be able to get what the relatedTarget without relying
// on the event
relatedTarget = document.activeElement as Element;
relatedTarget = this._getDocument().activeElement as Element;
}

if (!elementContains(this._root.current, relatedTarget as HTMLElement)) {
Expand Down Expand Up @@ -213,7 +214,7 @@ export class FocusTrapZone extends React.Component<IFocusTrapZoneProps, {}> impl

this._previouslyFocusedElementOutsideTrapZone = elementToFocusOnDismiss
? elementToFocusOnDismiss
: (document.activeElement as HTMLElement);
: (this._getDocument().activeElement as HTMLElement);
if (!disableFirstFocus && !elementContains(this._root.current, this._previouslyFocusedElementOutsideTrapZone)) {
this.focus();
}
Expand All @@ -226,12 +227,13 @@ export class FocusTrapZone extends React.Component<IFocusTrapZoneProps, {}> impl
return this !== value;
});

const activeElement = document.activeElement as HTMLElement;
const doc = this._getDocument();
const activeElement = doc.activeElement as HTMLElement;
if (
!ignoreExternalFocusing &&
this._previouslyFocusedElementOutsideTrapZone &&
typeof this._previouslyFocusedElementOutsideTrapZone.focus === 'function' &&
(elementContains(this._root.current, activeElement) || activeElement === document.body)
(elementContains(this._root.current, activeElement) || activeElement === doc.body)
) {
this._focusAsync(this._previouslyFocusedElementOutsideTrapZone);
}
Expand Down Expand Up @@ -277,7 +279,7 @@ export class FocusTrapZone extends React.Component<IFocusTrapZoneProps, {}> impl
}

if (FocusTrapZone._focusStack.length && this === FocusTrapZone._focusStack[FocusTrapZone._focusStack.length - 1]) {
const focusedElement = document.activeElement as HTMLElement;
const focusedElement = this._getDocument().activeElement as HTMLElement;

if (!elementContains(this._root.current, focusedElement)) {
this.focus();
Expand All @@ -304,4 +306,8 @@ export class FocusTrapZone extends React.Component<IFocusTrapZoneProps, {}> impl
}
}
};

private _getDocument(): Document {
return getDocument(this._root.current)!;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ export class FocusZone extends React.Component<IFocusZoneProps> implements IFocu

let parentElement = getParent(root, ALLOW_VIRTUAL_ELEMENTS);

while (parentElement && parentElement !== document.body && parentElement.nodeType === 1) {
while (parentElement && parentElement !== this._getDocument().body && parentElement.nodeType === 1) {
if (isElementFocusZone(parentElement)) {
this._isInnerZone = true;
break;
Expand All @@ -160,15 +160,15 @@ export class FocusZone extends React.Component<IFocusZoneProps> implements IFocu
this._updateTabIndexes();

if (this.props.defaultActiveElement) {
this._activeElement = getDocument()!.querySelector(this.props.defaultActiveElement) as HTMLElement;
this._activeElement = this._getDocument().querySelector(this.props.defaultActiveElement) as HTMLElement;
this.focus();
}
}
}

public componentDidUpdate(): void {
const { current: root } = this._root;
const doc = getDocument(root);
const doc = this._getDocument();

if (doc && this._lastIndexPath && (doc.activeElement === doc.body || doc.activeElement === root)) {
// The element has been removed after the render, attempt to restore focus.
Expand Down Expand Up @@ -309,16 +309,15 @@ export class FocusZone extends React.Component<IFocusZoneProps> implements IFocu

private _evaluateFocusBeforeRender(): void {
const { current: root } = this._root;
const doc = getDocument(root);

const doc = this._getDocument();
if (doc) {
const focusedElement = doc.activeElement as HTMLElement;

// Only update the index path if we are not parked on the root.
if (focusedElement !== root) {
const shouldRestoreFocus = elementContains(root, focusedElement, false);

this._lastIndexPath = shouldRestoreFocus ? getElementIndexPath(root as HTMLElement, doc.activeElement as HTMLElement) : undefined;
this._lastIndexPath = shouldRestoreFocus ? getElementIndexPath(root as HTMLElement, focusedElement) : undefined;
}
}
}
Expand Down Expand Up @@ -500,7 +499,7 @@ export class FocusZone extends React.Component<IFocusZoneProps> implements IFocu
return;
}

if (document.activeElement === this._root.current && this._isInnerZone) {
if (this._getDocument().activeElement === this._root.current && this._isInnerZone) {
// If this element has focus, it is being controlled by a parent.
// Ignore the keystroke.
return;
Expand Down Expand Up @@ -948,7 +947,7 @@ export class FocusZone extends React.Component<IFocusZoneProps> implements IFocu
private _getOwnerZone(element?: HTMLElement): HTMLElement | null {
let parentElement = getParent(element as HTMLElement, ALLOW_VIRTUAL_ELEMENTS);

while (parentElement && parentElement !== this._root.current && parentElement !== document.body) {
while (parentElement && parentElement !== this._root.current && parentElement !== this._getDocument().body) {
if (isElementFocusZone(parentElement)) {
return parentElement;
}
Expand Down Expand Up @@ -1060,4 +1059,8 @@ export class FocusZone extends React.Component<IFocusZoneProps> implements IFocu
private _portalContainsElement(element: HTMLElement): boolean {
return element && !!this._root.current && portalContainsElement(element, this._root.current);
}

private _getDocument(): Document {
return getDocument(this._root.current)!;
}
}

0 comments on commit 5c6b118

Please sign in to comment.