Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6aca76d
Add the ability for FocusZones to not wrap (vertically or horizontall…
jspurlin Feb 13, 2018
968c74a
Merge branch 'master' of https://github.com/OfficeDev/office-ui-fabri…
jspurlin Feb 13, 2018
3450460
update the example to make it more clear the changes I'm making
jspurlin Feb 13, 2018
9beb6c0
rush change
jspurlin Feb 13, 2018
3f4b516
remove unneeded resolution
jspurlin Feb 13, 2018
46a18bc
Remove an extra change from a different issue I'm working on
jspurlin Feb 13, 2018
f7c07c8
merge
jspurlin Feb 14, 2018
f8e6dd5
Update jspurlin-FocusZoneAddWrapProps_2018-02-13-16-53.json
jspurlin Feb 17, 2018
4b9902a
Update jspurlin-FocusZoneAddWrapProps_2018-02-13-16-53.json
jspurlin Feb 17, 2018
85b4e1a
Address feedback
jspurlin Feb 17, 2018
011f551
Update dom.ts
dzearing Feb 17, 2018
7a3f90c
Merge branch 'master' of https://github.com/OfficeDev/office-ui-fabri…
jspurlin Feb 18, 2018
6c7edea
Merge branch 'master' of https://github.com/OfficeDev/office-ui-fabri…
jspurlin Feb 20, 2018
f6cc8b9
change let to const
jspurlin Feb 20, 2018
ec4b935
Add FocusZoneProps for ContextualMenu
jspurlin Feb 20, 2018
040ea3f
fix test and add missing semicolon
jspurlin Feb 20, 2018
6cc9aec
update the max bundle size
jspurlin Feb 21, 2018
8e6d61f
merge from master
jspurlin Feb 21, 2018
1f1e385
update example to include key... must be a new rule
jspurlin Feb 22, 2018
b7be7a2
bumping the bundle size that went up due to the merge from master
jspurlin Feb 22, 2018
633906c
add a missing line
jspurlin Feb 22, 2018
2fbb4c9
Merge branch 'master' of https://github.com/OfficeDev/office-ui-fabri…
jspurlin Feb 22, 2018
84319b9
Merge branch 'master' of https://github.com/OfficeDev/office-ui-fabri…
jspurlin Feb 22, 2018
b3e8b64
Update FocusZone.tsx
dzearing Feb 22, 2018
2b28e22
update incorrectly cased variable
jspurlin Feb 22, 2018
ff23aad
Merge branch 'jspurlin/FocusZoneAddWrapProps' of https://github.com/j…
jspurlin Feb 22, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@uifabric/utilities",
"comment": "Focus/DOM: add the ability to find if an element (or any ancestor) contains a given attribute. Also, add a shouldrWapFocus function to the focus utility (which leverages the fild element attribute just described) which returns true if the given no wrap data attribute (data-no-vertical-wrap OR data-no-horizontal-wrap) exists and is set to true",
"type": "minor"
}
],
"packageName": "@uifabric/utilities",
"email": "jspurlin@microsoft.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "office-ui-fabric-react",
"comment": "FocusZone: Add the ability turn off directional wrapping on sections of a FocusZone",
"type": "minor"
}
],
"packageName": "office-ui-fabric-react",
"email": "jspurlin@microsoft.com"
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ describe('ContextualMenu', () => {
items={ items }
isSubMenu={ true }
onDismiss={ onDismissSpy }
arrowDirection={ FocusZoneDirection.horizontal }
focusZoneProps={ { direction: FocusZoneDirection.horizontal } }
/>
);

Expand All @@ -110,7 +110,7 @@ describe('ContextualMenu', () => {
items={ items }
isSubMenu={ true }
onDismiss={ onDismissSpy }
arrowDirection={ FocusZoneDirection.horizontal }
focusZoneProps={ { direction: FocusZoneDirection.bidirectional } }
/>
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react';
import { IContextualMenuProps, IContextualMenuItem, ContextualMenuItemType } from './ContextualMenu.types';
import { DirectionalHint } from '../../common/DirectionalHint';
import { FocusZone, FocusZoneDirection } from '../../FocusZone';
import { FocusZone, FocusZoneDirection, IFocusZoneProps } from '../../FocusZone';
import {
IMenuItemClassNames,
IContextualMenuClassNames,
Expand All @@ -25,7 +25,8 @@ import {
customizable,
getFirstFocusable,
getLastFocusable,
css
css,
shouldWrapFocus
} from '../../Utilities';
import { withResponsiveMode, ResponsiveMode } from '../../utilities/decorators/withResponsiveMode';
import { Callout } from '../../Callout';
Expand All @@ -36,6 +37,7 @@ import {
import {
VerticalDivider
} from '../../Divider';

export interface IContextualMenuState {
expandedMenuItemKey?: string;
dismissedMenuItemKey?: string;
Expand Down Expand Up @@ -109,8 +111,7 @@ export class ContextualMenu extends BaseComponent<IContextualMenuProps, IContext
gapSpace: 0,
directionalHint: DirectionalHint.bottomAutoEdge,
beakWidth: 16,
arrowDirection: FocusZoneDirection.vertical,
getMenuClassNames: getContextualMenuClassNames,
getMenuClassNames: getContextualMenuClassNames
};

private _host: HTMLElement;
Expand All @@ -124,6 +125,8 @@ export class ContextualMenu extends BaseComponent<IContextualMenuProps, IContext
private readonly _scrollIdleDelay: number = 250 /* ms */;
private _scrollIdleTimeoutId: number | undefined;

private _adjustedFocusZoneProps: IFocusZoneProps;

constructor(props: IContextualMenuProps) {
super(props);

Expand All @@ -135,6 +138,7 @@ export class ContextualMenu extends BaseComponent<IContextualMenuProps, IContext
this._warnDeprecations({
'targetPoint': 'target',
'useTargetPoint': 'target',
'arrowDirection': 'focusZoneProps'
});

this._isFocusingPreviousElement = false;
Expand Down Expand Up @@ -220,7 +224,8 @@ export class ContextualMenu extends BaseComponent<IContextualMenuProps, IContext
styles: customStyles,
theme,
calloutProps,
onRenderSubMenu = this._onRenderSubMenu
onRenderSubMenu = this._onRenderSubMenu,
focusZoneProps
} = this.props;

const menuClassNames = this.props.getMenuClassNames || getContextualMenuClassNames;
Expand All @@ -242,6 +247,8 @@ export class ContextualMenu extends BaseComponent<IContextualMenuProps, IContext
return false;
}

this._adjustedFocusZoneProps = { ...focusZoneProps, direction: this._getFocusZoneDirection() };

const hasCheckmarks = canAnyMenuItemsCheck(items);
const submenuProps = this.state.expandedMenuItemKey ? this._getSubmenuProps() : null;

Expand Down Expand Up @@ -309,8 +316,8 @@ export class ContextualMenu extends BaseComponent<IContextualMenuProps, IContext
{ title && <div className={ this._classNames.title } role='heading' aria-level={ 1 }> { title } </div> }
{ (items && items.length) ? (
<FocusZone
{...this._adjustedFocusZoneProps }
className={ this._classNames.root }
direction={ arrowDirection }
isCircularNavigation={ true }
allowTabKey={ true }
>
Expand Down Expand Up @@ -340,6 +347,19 @@ export class ContextualMenu extends BaseComponent<IContextualMenuProps, IContext
}
}

/**
* Gets the focusZoneDirection by using the arrowDirection if specified,
* the direction specificed in the focusZoneProps, or defaults to FocusZoneDirection.vertical
*/
private _getFocusZoneDirection() {
const {
arrowDirection,
focusZoneProps
} = this.props;
return arrowDirection !== undefined ? arrowDirection :
focusZoneProps && focusZoneProps.direction !== undefined ? focusZoneProps.direction : FocusZoneDirection.vertical;
}

private _onRenderSubMenu(subMenuProps: IContextualMenuProps) {
return <ContextualMenu { ...subMenuProps } />;
}
Expand Down Expand Up @@ -678,12 +698,10 @@ export class ContextualMenu extends BaseComponent<IContextualMenuProps, IContext

@autobind
private _onKeyDown(ev: React.KeyboardEvent<HTMLElement>) {
const submenuCloseKey = getRTL() ? KeyCodes.right : KeyCodes.left;

if (ev.which === KeyCodes.escape
|| ev.altKey
|| ev.metaKey
|| (ev.which === submenuCloseKey && this.props.isSubMenu && this.props.arrowDirection === FocusZoneDirection.vertical)) {
if (ev.which === KeyCodes.escape ||
ev.altKey ||
ev.metaKey ||
this._shouldCloseSubMenu(ev)) {
// When a user presses escape, we will try to refocus the previous focused element.
this._isFocusingPreviousElement = true;
ev.preventDefault();
Expand All @@ -692,6 +710,21 @@ export class ContextualMenu extends BaseComponent<IContextualMenuProps, IContext
}
}

/**
* Checks if the submenu should be closed
*/
@autobind
private _shouldCloseSubMenu(ev: React.KeyboardEvent<HTMLElement>): boolean {
const submenuCloseKey = getRTL() ? KeyCodes.right : KeyCodes.left;

if (ev.which !== submenuCloseKey || !this.props.isSubMenu) {
return false;
}

return this._adjustedFocusZoneProps.direction === FocusZoneDirection.vertical ||
(!!this._adjustedFocusZoneProps.checkForNoWrap && !shouldWrapFocus(ev.target as HTMLElement, 'data-no-horizontal-wrap'));
}

@autobind
private _onMenuKeyDown(ev: React.KeyboardEvent<HTMLElement>) {
if (ev.which === KeyCodes.escape || ev.altKey || ev.metaKey) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react';
import { ContextualMenu } from './ContextualMenu';
import { DirectionalHint } from '../../common/DirectionalHint';
import { FocusZoneDirection } from '../../FocusZone';
import { FocusZoneDirection, IFocusZoneProps } from '../../FocusZone';
import { IIconProps } from '../Icon/Icon.types';
import { ICalloutProps } from '../../Callout';
import { ITheme, IStyle } from '../../Styling';
Expand Down Expand Up @@ -169,7 +169,7 @@ export interface IContextualMenuProps extends React.Props<ContextualMenu>, IWith

/**
* Direction for arrow navigation of the ContextualMenu. Should only be specified if using custom-rendered menu items.
* @default FocusZoneDirection.vertical
* @deprecated Use focusZoneProps instead
*/
arrowDirection?: FocusZoneDirection;

Expand Down Expand Up @@ -219,6 +219,14 @@ export interface IContextualMenuProps extends React.Props<ContextualMenu>, IWith

/** Method to call when trying to render a submenu. */
onRenderSubMenu?: IRenderFunction<IContextualMenuProps>;

/**
* Props to pass down to the FocusZone.
* NOTE: the default FocusZoneDirection will be used unless a direction
* is specified in the focusZoneProps (even if other focusZoneProps are defined)
* @default {direction: FocusZoneDirection.vertical}
*/
focusZoneProps?: IFocusZoneProps;
}

export interface IContextualMenuItem {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { ContextualMenuBasicExample } from './examples/ContextualMenu.Basic.Exam
import { ContextualMenuIconExample } from './examples/ContextualMenu.Icon.Example';
import { ContextualMenuSectionExample } from './examples/ContextualMenu.Section.Example';
import { ContextualMenuSubmenuExample } from './examples/ContextualMenu.Submenu.Example';
import { ContextualMenuCustomizationWithNoWrapExample } from './examples/ContextualMenu.CustomizationWithNoWrap.Example';
import { ContextualMenuCheckmarksExample } from './examples/ContextualMenu.Checkmarks.Example';
import { ContextualMenuDirectionalExample } from './examples/ContextualMenu.Directional.Example';
import { ContextualMenuCustomizationExample } from './examples/ContextualMenu.Customization.Example';
Expand All @@ -20,6 +21,7 @@ const ContextualMenuBasicExampleCode = require('!raw-loader!office-ui-fabric-rea
const ContextualMenuIconExampleCode = require('!raw-loader!office-ui-fabric-react/src/components/ContextualMenu/examples/ContextualMenu.Icon.Example.tsx') as string;
const ContextualMenuSectionExampleCode = require('!raw-loader!office-ui-fabric-react/src/components/ContextualMenu/examples/ContextualMenu.Section.Example.tsx') as string;
const ContextualMenuSubmenuExampleCode = require('!raw-loader!office-ui-fabric-react/src/components/ContextualMenu/examples/ContextualMenu.Submenu.Example.tsx') as string;
const ContextualMenuCustomizationWithNoWrapExampleCode = require('!raw-loader!office-ui-fabric-react/src/components/ContextualMenu/examples/ContextualMenu.CustomizationWithNoWrap.Example.tsx') as string;
const ContextualMenuCheckmarksExampleCode = require('!raw-loader!office-ui-fabric-react/src/components/ContextualMenu/examples/ContextualMenu.Checkmarks.Example.tsx') as string;
const ContextualMenuDirectionalExampleCode = require('!raw-loader!office-ui-fabric-react/src/components/ContextualMenu/examples/ContextualMenu.Directional.Example.tsx') as string;
const ContextualMenuCustomizationExampleCode = require('!raw-loader!office-ui-fabric-react/src/components/ContextualMenu/examples/ContextualMenu.Customization.Example.tsx') as string;
Expand Down Expand Up @@ -76,6 +78,12 @@ export class ContextualMenuPage extends React.Component<IComponentDemoPageProps,
>
<ContextualMenuCustomizationExample />
</ExampleCard>
<ExampleCard
title='ContextualMenu with customized submenus and noWrap attributes'
code={ ContextualMenuSubmenuExampleCode }
>
<ContextualMenuCustomizationWithNoWrapExample />
</ExampleCard>
<ExampleCard
title='ContextualMenu with a scroll bar and fixed direction'
code={ ContextualMenuWithScrollBarExampleCode }
Expand Down
Loading