diff --git a/common/changes/office-ui-fabric-react/jolore-focusZoneUpdate_2018-04-07-00-43.json b/common/changes/office-ui-fabric-react/jolore-focusZoneUpdate_2018-04-07-00-43.json
new file mode 100644
index 00000000000000..0fc71f8d07094b
--- /dev/null
+++ b/common/changes/office-ui-fabric-react/jolore-focusZoneUpdate_2018-04-07-00-43.json
@@ -0,0 +1,11 @@
+{
+ "changes": [
+ {
+ "packageName": "office-ui-fabric-react",
+ "comment": "FocusZone: updating to update alignment on click.",
+ "type": "patch"
+ }
+ ],
+ "packageName": "office-ui-fabric-react",
+ "email": "jolore@microsoft.com"
+}
diff --git a/packages/experiments/src/components/CommandBar/__snapshots__/CommandBar.test.tsx.snap b/packages/experiments/src/components/CommandBar/__snapshots__/CommandBar.test.tsx.snap
index 7c7eab154bbbcb..d9fa592f5519fa 100644
--- a/packages/experiments/src/components/CommandBar/__snapshots__/CommandBar.test.tsx.snap
+++ b/packages/experiments/src/components/CommandBar/__snapshots__/CommandBar.test.tsx.snap
@@ -44,6 +44,7 @@ exports[`CommandBar renders commands correctly 1`] = `
flex-grow: 1;
}
data-focuszone-id="FocusZone0"
+ onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDownCapture={[Function]}
@@ -286,6 +287,7 @@ exports[`CommandBar renders commands correctly 1`] = `
flex-shrink: 0;
}
data-focuszone-id="FocusZone7"
+ onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDownCapture={[Function]}
diff --git a/packages/office-ui-fabric-react/src/components/Breadcrumb/__snapshots__/Breadcrumb.test.tsx.snap b/packages/office-ui-fabric-react/src/components/Breadcrumb/__snapshots__/Breadcrumb.test.tsx.snap
index 288b828f23dcfc..d262d479dbead1 100644
--- a/packages/office-ui-fabric-react/src/components/Breadcrumb/__snapshots__/Breadcrumb.test.tsx.snap
+++ b/packages/office-ui-fabric-react/src/components/Breadcrumb/__snapshots__/Breadcrumb.test.tsx.snap
@@ -27,6 +27,7 @@ exports[`Breadcrumb renders breadcumb correctly 1`] = `
aria-labelledby={undefined}
className="ms-FocusZone"
data-focuszone-id="FocusZone0"
+ onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDownCapture={[Function]}
@@ -171,6 +172,7 @@ exports[`Breadcrumb renders breadcumb correctly 2`] = `
aria-labelledby={undefined}
className="ms-FocusZone"
data-focuszone-id="FocusZone5"
+ onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDownCapture={[Function]}
@@ -380,6 +382,7 @@ exports[`Breadcrumb renders breadcumb correctly 3`] = `
aria-labelledby={undefined}
className="ms-FocusZone"
data-focuszone-id="FocusZone11"
+ onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDownCapture={[Function]}
diff --git a/packages/office-ui-fabric-react/src/components/Calendar/__snapshots__/Calendar.test.tsx.snap b/packages/office-ui-fabric-react/src/components/Calendar/__snapshots__/Calendar.test.tsx.snap
index 507065a96d6f5d..da925f1c914748 100644
--- a/packages/office-ui-fabric-react/src/components/Calendar/__snapshots__/Calendar.test.tsx.snap
+++ b/packages/office-ui-fabric-react/src/components/Calendar/__snapshots__/Calendar.test.tsx.snap
@@ -91,6 +91,7 @@ exports[`Calendar Test rendering simplest calendar Renders simple calendar corre
aria-labelledby={undefined}
className="ms-FocusZone"
data-focuszone-id="FocusZone12"
+ onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDownCapture={[Function]}
@@ -958,6 +959,7 @@ exports[`Calendar Test rendering simplest calendar Renders simple calendar corre
aria-labelledby={undefined}
className="ms-FocusZone"
data-focuszone-id="FocusZone13"
+ onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDownCapture={[Function]}
diff --git a/packages/office-ui-fabric-react/src/components/CommandBar/__snapshots__/CommandBar.test.tsx.snap b/packages/office-ui-fabric-react/src/components/CommandBar/__snapshots__/CommandBar.test.tsx.snap
index cdfa05f114431b..f4d10a32c15ac3 100644
--- a/packages/office-ui-fabric-react/src/components/CommandBar/__snapshots__/CommandBar.test.tsx.snap
+++ b/packages/office-ui-fabric-react/src/components/CommandBar/__snapshots__/CommandBar.test.tsx.snap
@@ -9,6 +9,7 @@ exports[`CommandBar renders CommandBar correctly 1`] = `
aria-labelledby={undefined}
className="ms-FocusZone"
data-focuszone-id="FocusZone1"
+ onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDownCapture={[Function]}
diff --git a/packages/office-ui-fabric-react/src/components/DetailsList/__snapshots__/DetailsHeader.test.tsx.snap b/packages/office-ui-fabric-react/src/components/DetailsList/__snapshots__/DetailsHeader.test.tsx.snap
index 311fa3eb38b373..6240400730b830 100644
--- a/packages/office-ui-fabric-react/src/components/DetailsList/__snapshots__/DetailsHeader.test.tsx.snap
+++ b/packages/office-ui-fabric-react/src/components/DetailsList/__snapshots__/DetailsHeader.test.tsx.snap
@@ -8,6 +8,7 @@ exports[`DetailsHeader can render 1`] = `
className="ms-FocusZone ms-DetailsHeader"
data-automationid="DetailsHeader"
data-focuszone-id="FocusZone1"
+ onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDownCapture={[Function]}
diff --git a/packages/office-ui-fabric-react/src/components/DetailsList/__snapshots__/DetailsList.test.tsx.snap b/packages/office-ui-fabric-react/src/components/DetailsList/__snapshots__/DetailsList.test.tsx.snap
index d4d66656bcecad..fbdb6a331f19d2 100644
--- a/packages/office-ui-fabric-react/src/components/DetailsList/__snapshots__/DetailsList.test.tsx.snap
+++ b/packages/office-ui-fabric-react/src/components/DetailsList/__snapshots__/DetailsList.test.tsx.snap
@@ -34,6 +34,7 @@ exports[`DetailsList renders List correctly 1`] = `
className="ms-FocusZone ms-DetailsHeader"
data-automationid="DetailsHeader"
data-focuszone-id="FocusZone1"
+ onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDownCapture={[Function]}
@@ -203,6 +204,7 @@ exports[`DetailsList renders List correctly 1`] = `
className="ms-FocusZone"
data-focuszone-id="FocusZone2"
onBlur={[Function]}
+ onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDownCapture={[Function]}
diff --git a/packages/office-ui-fabric-react/src/components/Facepile/__snapshots__/Facepile.test.tsx.snap b/packages/office-ui-fabric-react/src/components/Facepile/__snapshots__/Facepile.test.tsx.snap
index a75223fb0d25fa..62c741bd429e4a 100644
--- a/packages/office-ui-fabric-react/src/components/Facepile/__snapshots__/Facepile.test.tsx.snap
+++ b/packages/office-ui-fabric-react/src/components/Facepile/__snapshots__/Facepile.test.tsx.snap
@@ -12,6 +12,7 @@ exports[`Facepile renders Facepile correctly 1`] = `
aria-labelledby={undefined}
className="ms-FocusZone ms-Facepile-members"
data-focuszone-id="FocusZone1"
+ onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDownCapture={[Function]}
diff --git a/packages/office-ui-fabric-react/src/components/FocusZone/FocusZone.test.tsx b/packages/office-ui-fabric-react/src/components/FocusZone/FocusZone.test.tsx
index d5972db64ea2c6..21ee8495b7b589 100644
--- a/packages/office-ui-fabric-react/src/components/FocusZone/FocusZone.test.tsx
+++ b/packages/office-ui-fabric-react/src/components/FocusZone/FocusZone.test.tsx
@@ -729,6 +729,87 @@ describe('FocusZone', () => {
expect(lastFocusedElement).toBe(buttonA);
});
+ it('click resets focus alignment when bidirectional', () => {
+ const component = ReactTestUtils.renderIntoDocument(
+
+
+
+
+
+
+
+
+ );
+
+ const focusZone = ReactDOM.findDOMNode(component as React.ReactInstance).firstChild as Element;
+ const buttonA = focusZone.querySelector('.a') as HTMLElement;
+ const buttonB = focusZone.querySelector('.b') as HTMLElement;
+ const buttonC = focusZone.querySelector('.c') as HTMLElement;
+ const buttonD = focusZone.querySelector('.d') as HTMLElement;
+
+ // Set up a grid like so:
+ // A B
+ // C D
+ setupElement(buttonA, {
+ clientRect: {
+ top: 0,
+ bottom: 20,
+ left: 0,
+ right: 20
+ }
+ });
+
+ setupElement(buttonB, {
+ clientRect: {
+ top: 0,
+ bottom: 20,
+ left: 20,
+ right: 40
+ }
+ });
+
+ setupElement(buttonC, {
+ clientRect: {
+ top: 20,
+ bottom: 40,
+ left: 0,
+ right: 20
+ }
+ });
+
+ setupElement(buttonD, {
+ clientRect: {
+ top: 20,
+ bottom: 40,
+ left: 20,
+ right: 40
+ }
+ });
+
+ // Focus the first button.
+ ReactTestUtils.Simulate.focus(buttonA);
+ expect(lastFocusedElement).toBe(buttonA);
+
+ // Clicking on b should focus b, and reset the focus alignment to the second column
+ // note that a click in a browser fires mouseDown, focus, then click events
+ ReactTestUtils.Simulate.focus(buttonB);
+ ReactTestUtils.Simulate.click(buttonB);
+ expect(lastFocusedElement).toBe(buttonB);
+
+ // Pressing down should go to d.
+ ReactTestUtils.Simulate.keyDown(focusZone, { which: KeyCodes.down });
+ expect(lastFocusedElement).toBe(buttonD);
+
+ // Clicking on c should focus c, and reset the focus alignment to the first column
+ ReactTestUtils.Simulate.focus(buttonC);
+ ReactTestUtils.Simulate.click(buttonC);
+ expect(lastFocusedElement).toBe(buttonC);
+
+ // Pressing up should go to a.
+ ReactTestUtils.Simulate.keyDown(focusZone, { which: KeyCodes.up });
+ expect(lastFocusedElement).toBe(buttonA);
+ });
+
it('correctly skips data-not-focusable elements', () => {
const component = ReactTestUtils.renderIntoDocument(
diff --git a/packages/office-ui-fabric-react/src/components/FocusZone/FocusZone.tsx b/packages/office-ui-fabric-react/src/components/FocusZone/FocusZone.tsx
index 6823e02c0e7b1d..68dac458c28098 100644
--- a/packages/office-ui-fabric-react/src/components/FocusZone/FocusZone.tsx
+++ b/packages/office-ui-fabric-react/src/components/FocusZone/FocusZone.tsx
@@ -146,6 +146,7 @@ export class FocusZone extends BaseComponent implements IFo
aria-describedby={ ariaDescribedBy }
onKeyDown={ this._onKeyDown }
onFocus={ this._onFocus }
+ onClick={ this._onClick }
onMouseDownCapture={ this._onMouseDown }
>
{ this.props.children }
@@ -212,23 +213,34 @@ export class FocusZone extends BaseComponent implements IFo
private _onFocus = (ev: React.FocusEvent): void => {
const { onActiveElementChanged } = this.props;
- if (this._isImmediateDescendantOfZone(ev.target as HTMLElement)) {
- this._activeElement = ev.target as HTMLElement;
- this._setFocusAlignment(this._activeElement);
+ this._setTargetElement(ev.target, false);
+ if (onActiveElementChanged) {
+ onActiveElementChanged(this._activeElement as HTMLElement, ev);
+ }
+ }
+
+ private _onClick = (ev: React.MouseEvent): void => {
+ this._setTargetElement(ev.target, true);
+ }
+
+ private _setTargetElement = (target: EventTarget, forceUpdateAlignment?: boolean): void => {
+ const { onActiveElementChanged } = this.props;
+
+ if (this._isImmediateDescendantOfZone(target as HTMLElement)) {
+ this._activeElement = target as HTMLElement;
+ this._setFocusAlignment(this._activeElement, forceUpdateAlignment, forceUpdateAlignment);
} else {
- let parentElement = ev.target as HTMLElement;
+ let parentElement = target as HTMLElement;
while (parentElement && parentElement !== this._root.value) {
if (isElementTabbable(parentElement) && this._isImmediateDescendantOfZone(parentElement)) {
this._activeElement = parentElement;
+ this._setFocusAlignment(this._activeElement, forceUpdateAlignment, forceUpdateAlignment);
break;
}
parentElement = getParent(parentElement, ALLOW_VIRTUAL_ELEMENTS) as HTMLElement;
}
}
- if (onActiveElementChanged) {
- onActiveElementChanged(this._activeElement as HTMLElement, ev);
- }
}
/**
diff --git a/packages/office-ui-fabric-react/src/components/Nav/__snapshots__/Nav.test.tsx.snap b/packages/office-ui-fabric-react/src/components/Nav/__snapshots__/Nav.test.tsx.snap
index b1e5e6fd2fb617..fbbe421b3f491d 100644
--- a/packages/office-ui-fabric-react/src/components/Nav/__snapshots__/Nav.test.tsx.snap
+++ b/packages/office-ui-fabric-react/src/components/Nav/__snapshots__/Nav.test.tsx.snap
@@ -6,6 +6,7 @@ exports[`Nav renders Nav correctly 1`] = `
aria-labelledby={undefined}
className="ms-FocusZone"
data-focuszone-id="FocusZone0"
+ onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDownCapture={[Function]}
diff --git a/packages/office-ui-fabric-react/src/components/Pivot/__snapshots__/Pivot.test.tsx.snap b/packages/office-ui-fabric-react/src/components/Pivot/__snapshots__/Pivot.test.tsx.snap
index 225f07e583fc7f..3b4aa053821ef3 100644
--- a/packages/office-ui-fabric-react/src/components/Pivot/__snapshots__/Pivot.test.tsx.snap
+++ b/packages/office-ui-fabric-react/src/components/Pivot/__snapshots__/Pivot.test.tsx.snap
@@ -7,6 +7,7 @@ exports[`Pivot renders Pivot correctly 1`] = `
aria-labelledby={undefined}
className="ms-FocusZone"
data-focuszone-id="FocusZone1"
+ onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDownCapture={[Function]}
diff --git a/packages/office-ui-fabric-react/src/components/Rating/__snapshots__/Rating.test.tsx.snap b/packages/office-ui-fabric-react/src/components/Rating/__snapshots__/Rating.test.tsx.snap
index 686bdd8cd92670..a93e9308308de3 100644
--- a/packages/office-ui-fabric-react/src/components/Rating/__snapshots__/Rating.test.tsx.snap
+++ b/packages/office-ui-fabric-react/src/components/Rating/__snapshots__/Rating.test.tsx.snap
@@ -18,6 +18,7 @@ exports[`Rating Renders Rating correctly 1`] = `
}
data-focuszone-id="FocusZone2"
data-is-focusable={false}
+ onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDownCapture={[Function]}
diff --git a/packages/office-ui-fabric-react/src/components/SwatchColorPicker/__snapshots__/SwatchColorPicker.test.tsx.snap b/packages/office-ui-fabric-react/src/components/SwatchColorPicker/__snapshots__/SwatchColorPicker.test.tsx.snap
index 0a55445b0bccb3..8177cbed6ad150 100644
--- a/packages/office-ui-fabric-react/src/components/SwatchColorPicker/__snapshots__/SwatchColorPicker.test.tsx.snap
+++ b/packages/office-ui-fabric-react/src/components/SwatchColorPicker/__snapshots__/SwatchColorPicker.test.tsx.snap
@@ -14,6 +14,7 @@ exports[`SwatchColorPicker renders SwatchColorPicker correctly 1`] = `
}
data-focuszone-id="FocusZone3"
onBlur={[Function]}
+ onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDownCapture={[Function]}
diff --git a/packages/office-ui-fabric-react/src/components/pickers/__snapshots__/BasePicker.test.tsx.snap b/packages/office-ui-fabric-react/src/components/pickers/__snapshots__/BasePicker.test.tsx.snap
index 6ed2487d4f220f..6ba81af3ad968b 100644
--- a/packages/office-ui-fabric-react/src/components/pickers/__snapshots__/BasePicker.test.tsx.snap
+++ b/packages/office-ui-fabric-react/src/components/pickers/__snapshots__/BasePicker.test.tsx.snap
@@ -10,6 +10,7 @@ exports[`Pickers BasePicker renders BasePicker correctly 1`] = `
aria-labelledby={undefined}
className="ms-FocusZone"
data-focuszone-id="FocusZone0"
+ onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDownCapture={[Function]}
@@ -77,6 +78,7 @@ exports[`Pickers TagPicker renders TagPicker correctly 1`] = `
aria-labelledby={undefined}
className="ms-FocusZone"
data-focuszone-id="FocusZone17"
+ onClick={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onMouseDownCapture={[Function]}