diff --git a/common/changes/@uifabric/utilities/fix-fabric-isfocusvisible_2018-04-25-01-59.json b/common/changes/@uifabric/utilities/fix-fabric-isfocusvisible_2018-04-25-01-59.json
new file mode 100644
index 0000000000000..a9d39fa272cf4
--- /dev/null
+++ b/common/changes/@uifabric/utilities/fix-fabric-isfocusvisible_2018-04-25-01-59.json
@@ -0,0 +1,11 @@
+{
+ "changes": [
+ {
+ "packageName": "@uifabric/utilities",
+ "comment": "Adding `isDirectionalKeyCode` helper.",
+ "type": "minor"
+ }
+ ],
+ "packageName": "@uifabric/utilities",
+ "email": "dzearing@microsoft.com"
+}
\ No newline at end of file
diff --git a/common/changes/office-ui-fabric-react/fix-fabric-isfocusvisible_2018-04-25-01-59.json b/common/changes/office-ui-fabric-react/fix-fabric-isfocusvisible_2018-04-25-01-59.json
new file mode 100644
index 0000000000000..485a397792895
--- /dev/null
+++ b/common/changes/office-ui-fabric-react/fix-fabric-isfocusvisible_2018-04-25-01-59.json
@@ -0,0 +1,11 @@
+{
+ "changes": [
+ {
+ "packageName": "office-ui-fabric-react",
+ "comment": "Fabric: the isFocusVisible class is no added to the Fabric component again, to preserve backwards compatibility. Also fixing index file to export the types.",
+ "type": "minor"
+ }
+ ],
+ "packageName": "office-ui-fabric-react",
+ "email": "dzearing@microsoft.com"
+}
\ No newline at end of file
diff --git a/packages/office-ui-fabric-react/src/components/Fabric/Fabric.styles.ts b/packages/office-ui-fabric-react/src/components/Fabric/Fabric.styles.ts
index 746a7facdcbc9..d6e533f41771f 100644
--- a/packages/office-ui-fabric-react/src/components/Fabric/Fabric.styles.ts
+++ b/packages/office-ui-fabric-react/src/components/Fabric/Fabric.styles.ts
@@ -15,11 +15,13 @@ export const getStyles = (props: IFabricStyleProps): IFabricStyles => {
const {
theme,
className,
+ isFocusVisible
} = props;
return {
root: [
'ms-Fabric',
+ isFocusVisible && 'is-focusVisible',
theme.fonts.medium,
{
color: theme.palette.neutralPrimary,
diff --git a/packages/office-ui-fabric-react/src/components/Fabric/Fabric.test.tsx b/packages/office-ui-fabric-react/src/components/Fabric/Fabric.test.tsx
new file mode 100644
index 0000000000000..5aaebd7e9c05c
--- /dev/null
+++ b/packages/office-ui-fabric-react/src/components/Fabric/Fabric.test.tsx
@@ -0,0 +1,14 @@
+import * as React from 'react';
+import * as renderer from 'react-test-renderer';
+import { Fabric } from './Fabric';
+
+describe('Fabric', () => {
+ it('renders correctly', () => {
+ const component = renderer.create(
+ test
+ );
+ const tree = component.toJSON();
+ expect(tree).toMatchSnapshot();
+ });
+
+});
diff --git a/packages/office-ui-fabric-react/src/components/Fabric/Fabric.tsx b/packages/office-ui-fabric-react/src/components/Fabric/Fabric.tsx
index 1998193d3c869..9f4a1de1b5d66 100644
--- a/packages/office-ui-fabric-react/src/components/Fabric/Fabric.tsx
+++ b/packages/office-ui-fabric-react/src/components/Fabric/Fabric.tsx
@@ -1,10 +1,13 @@
import * as React from 'react';
import {
BaseComponent,
+ createRef,
customizable,
getNativeProps,
divProperties,
- classNamesFunction
+ classNamesFunction,
+ getWindow,
+ isDirectionalKeyCode
} from '../../Utilities';
import { getStyles } from './Fabric.styles';
import { IFabricProps, IFabricStyleProps, IFabricStyles } from './Fabric.types';
@@ -12,16 +15,49 @@ import { IFabricProps, IFabricStyleProps, IFabricStyles } from './Fabric.types';
const getClassNames = classNamesFunction();
@customizable('Fabric', ['theme'])
-export class Fabric extends BaseComponent {
+export class Fabric extends BaseComponent {
+ private _rootElement = createRef();
+
+ constructor(props: IFabricProps) {
+ super(props);
+ this.state = { isFocusVisible: false };
+ }
+
public render() {
- const classNames = getClassNames(getStyles, this.props as IFabricStyleProps);
+ const classNames = getClassNames(getStyles,
+ {
+ ...this.props as IFabricStyleProps,
+ ...this.state
+ });
const divProps = getNativeProps(this.props, divProperties);
return (
);
}
+
+ public componentDidMount(): void {
+ const win = getWindow(this._rootElement.value);
+
+ if (win) {
+ this._events.on(win, 'mousedown', this._onMouseDown, true);
+ this._events.on(win, 'keydown', this._onKeyDown, true);
+ }
+ }
+
+ private _onMouseDown = (ev: MouseEvent): void => {
+ this.setState({ isFocusVisible: false });
+ }
+
+ private _onKeyDown = (ev: KeyboardEvent): void => {
+ if (isDirectionalKeyCode(ev.which)) {
+ this.setState({ isFocusVisible: true });
+ }
+ }
}
diff --git a/packages/office-ui-fabric-react/src/components/Fabric/Fabric.types.ts b/packages/office-ui-fabric-react/src/components/Fabric/Fabric.types.ts
index 7a521e18e5bad..9949f90bb89a1 100644
--- a/packages/office-ui-fabric-react/src/components/Fabric/Fabric.types.ts
+++ b/packages/office-ui-fabric-react/src/components/Fabric/Fabric.types.ts
@@ -7,6 +7,7 @@ export interface IFabricProps extends React.HTMLAttributes {
export interface IFabricStyleProps extends IFabricProps {
theme: ITheme;
+ isFocusVisible: boolean;
}
export interface IFabricStyles {
diff --git a/packages/office-ui-fabric-react/src/components/Fabric/__snapshots__/Fabric.test.tsx.snap b/packages/office-ui-fabric-react/src/components/Fabric/__snapshots__/Fabric.test.tsx.snap
new file mode 100644
index 0000000000000..12987076b5889
--- /dev/null
+++ b/packages/office-ui-fabric-react/src/components/Fabric/__snapshots__/Fabric.test.tsx.snap
@@ -0,0 +1,30 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Fabric renders correctly 1`] = `
+
+ test
+
+`;
diff --git a/packages/office-ui-fabric-react/src/components/Fabric/index.ts b/packages/office-ui-fabric-react/src/components/Fabric/index.ts
index 3852b24a3fb89..5ada46526bbab 100644
--- a/packages/office-ui-fabric-react/src/components/Fabric/index.ts
+++ b/packages/office-ui-fabric-react/src/components/Fabric/index.ts
@@ -1 +1,2 @@
export * from './Fabric';
+export * from './Fabric.types';
diff --git a/packages/utilities/src/index.ts b/packages/utilities/src/index.ts
index 7a5be668bb502..962253d3a2a66 100644
--- a/packages/utilities/src/index.ts
+++ b/packages/utilities/src/index.ts
@@ -31,6 +31,7 @@ export * from './hoist';
export * from './hoistStatics';
export * from './initializeFocusRects';
export * from './initials';
+export * from './keyboard';
export * from './language';
export * from './math';
export * from './memoize';
@@ -42,4 +43,4 @@ export * from './rtl';
export * from './scroll';
export * from './string';
export * from './styled';
-export * from './warn';
\ No newline at end of file
+export * from './warn';
diff --git a/packages/utilities/src/initializeFocusRects.ts b/packages/utilities/src/initializeFocusRects.ts
index 444a87ae8bc7d..9a60e2df47693 100644
--- a/packages/utilities/src/initializeFocusRects.ts
+++ b/packages/utilities/src/initializeFocusRects.ts
@@ -1,19 +1,7 @@
import { getWindow } from './dom';
-import { KeyCodes } from './KeyCodes';
-import { KeyboardEvent } from '../../../common/temp/node_modules/@types/react';
+import { isDirectionalKeyCode } from './keyboard';
export const IsFocusVisibleClassName = 'ms-Fabric--isFocusVisible';
-const DirectionalKeyCodes = [
- KeyCodes.up,
- KeyCodes.down,
- KeyCodes.left,
- KeyCodes.right,
- KeyCodes.home,
- KeyCodes.end,
- KeyCodes.tab,
- KeyCodes.pageUp,
- KeyCodes.pageDown
-];
/**
* Initializes the logic which:
@@ -51,14 +39,13 @@ function _onMouseDown(ev: MouseEvent): void {
}
}
-function _onKeyDown(ev: KeyboardEvent): void {
+function _onKeyDown(ev: KeyboardEvent): void {
const win = getWindow(ev.target as Element);
if (win) {
const { classList } = win.document.body;
- const isDirectionalKeyCode = DirectionalKeyCodes.indexOf(ev.which) > -1;
- if (isDirectionalKeyCode && !classList.contains(IsFocusVisibleClassName)) {
+ if (isDirectionalKeyCode(ev.which) && !classList.contains(IsFocusVisibleClassName)) {
classList.add(IsFocusVisibleClassName);
}
}
diff --git a/packages/utilities/src/keyboard.test.ts b/packages/utilities/src/keyboard.test.ts
new file mode 100644
index 0000000000000..f0e44b1a4065c
--- /dev/null
+++ b/packages/utilities/src/keyboard.test.ts
@@ -0,0 +1,9 @@
+import { isDirectionalKeyCode } from './keyboard';
+import { KeyCodes } from './KeyCodes';
+
+describe('isDirectionalKeyCode', () => {
+ it('can return the expected value', () => {
+ isDirectionalKeyCode(KeyCodes.up);
+ isDirectionalKeyCode(KeyCodes.enter);
+ });
+});
\ No newline at end of file
diff --git a/packages/utilities/src/keyboard.ts b/packages/utilities/src/keyboard.ts
new file mode 100644
index 0000000000000..22e7552c52fac
--- /dev/null
+++ b/packages/utilities/src/keyboard.ts
@@ -0,0 +1,20 @@
+import { KeyCodes } from './KeyCodes';
+
+const DirectionalKeyCodes: { [key: number]: number } = {
+ [KeyCodes.up]: 1,
+ [KeyCodes.down]: 1,
+ [KeyCodes.left]: 1,
+ [KeyCodes.right]: 1,
+ [KeyCodes.home]: 1,
+ [KeyCodes.end]: 1,
+ [KeyCodes.tab]: 1,
+ [KeyCodes.pageUp]: 1,
+ [KeyCodes.pageDown]: 1
+};
+
+/**
+ * Returns true if the keycode is a directional keyboard key.
+ */
+export function isDirectionalKeyCode(which: number): boolean {
+ return !!DirectionalKeyCodes[which];
+}