diff --git a/common/changes/master_2017-05-02-22-52.json b/common/changes/master_2017-05-02-22-52.json index d5eb7237a25aa..2d85e4f327a09 100644 --- a/common/changes/master_2017-05-02-22-52.json +++ b/common/changes/master_2017-05-02-22-52.json @@ -8,3 +8,4 @@ ], "email": "micahgodbolt@gmail.com" } + diff --git a/common/changes/overflow-set_2017-04-17-21-47.json b/common/changes/overflow-set_2017-04-17-21-47.json new file mode 100644 index 0000000000000..243fab914bc62 --- /dev/null +++ b/common/changes/overflow-set_2017-04-17-21-47.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "office-ui-fabric-react", + "comment": "OverflowSet: New Overflow Set componet to create sets of elements with overflow showing in callout", + "type": "patch" + } + ], + "email": "micahgodbolt@gmail.com" +} \ No newline at end of file diff --git a/packages/office-ui-fabric-react/src/OverflowSet.ts b/packages/office-ui-fabric-react/src/OverflowSet.ts new file mode 100644 index 0000000000000..ec6e7f73fadbc --- /dev/null +++ b/packages/office-ui-fabric-react/src/OverflowSet.ts @@ -0,0 +1 @@ +export * from './components/OverflowSet/index'; diff --git a/packages/office-ui-fabric-react/src/components/OverflowSet/OverflowSet.Props.ts b/packages/office-ui-fabric-react/src/components/OverflowSet/OverflowSet.Props.ts new file mode 100644 index 0000000000000..8abb30b5f6fa8 --- /dev/null +++ b/packages/office-ui-fabric-react/src/components/OverflowSet/OverflowSet.Props.ts @@ -0,0 +1,29 @@ +import * as React from 'react'; +import { OverflowSet } from './OverflowSet'; +import { IContextualMenuItem } from '../../ContextualMenu'; +import { IButtonProps } from '../../Button'; +import { IRenderFunction } from '../../Utilities'; +import { IObjectWithKey } from '../../Selection'; + +export interface IOverflowSetProps extends React.Props { + + /** + * An array of items to be rendered by your onRenderItem function in the primary content area + */ + items?: any[] | IObjectWithKey[]; + + /** + * An array of items to be passed to overflow contextual menu + */ + overflowItems?: IContextualMenuItem[]; + + /** + * Method to call when trying to render an item. + */ + onRenderItem: IRenderFunction; + + /** + * Rendering method for overflow button and contextual menu. + */ + onRenderOverflowButton: IRenderFunction; +} diff --git a/packages/office-ui-fabric-react/src/components/OverflowSet/OverflowSet.scss b/packages/office-ui-fabric-react/src/components/OverflowSet/OverflowSet.scss new file mode 100644 index 0000000000000..d46438c8214b4 --- /dev/null +++ b/packages/office-ui-fabric-react/src/components/OverflowSet/OverflowSet.scss @@ -0,0 +1,11 @@ +@import '../../common/common'; + +.root { + position: relative; + display: flex; + flex-wrap: nowrap; +} + +.item { + flex-shrink: 0; +} diff --git a/packages/office-ui-fabric-react/src/components/OverflowSet/OverflowSet.tsx b/packages/office-ui-fabric-react/src/components/OverflowSet/OverflowSet.tsx new file mode 100644 index 0000000000000..cdade53e7e6f7 --- /dev/null +++ b/packages/office-ui-fabric-react/src/components/OverflowSet/OverflowSet.tsx @@ -0,0 +1,46 @@ +import * as React from 'react'; +import { + css, + autobind, + BaseComponent +} from '../../Utilities'; +import { IButtonProps } from '../../Button'; +import { IOverflowSetProps } from './OverflowSet.Props'; +import { FocusZone, FocusZoneDirection } from '../../FocusZone'; + +import * as stylesImport from './OverflowSet.scss'; +const styles: any = stylesImport; + +export class OverflowSet extends BaseComponent { + + public render() { + let { + items, + overflowItems, + onRenderOverflowButton + } = this.props; + + const overflowButtonProps: IButtonProps = { + menuProps: { items: overflowItems } + }; + + return ( + + { items && this._onRenderItems(items) } + { overflowItems.length && onRenderOverflowButton(overflowButtonProps) } + + ); + } + + @autobind + private _onRenderItems(items: any[]): JSX.Element[] { + return items.map((item, i) => { + let key = item.key ? item.key : i; + return ( +
+ { this.props.onRenderItem(item) } +
+ ); + }); + } +} diff --git a/packages/office-ui-fabric-react/src/components/OverflowSet/OverflowSetPage.tsx b/packages/office-ui-fabric-react/src/components/OverflowSet/OverflowSetPage.tsx new file mode 100644 index 0000000000000..16b0f8f653fcf --- /dev/null +++ b/packages/office-ui-fabric-react/src/components/OverflowSet/OverflowSetPage.tsx @@ -0,0 +1,49 @@ +import * as React from 'react'; +import { Link } from 'office-ui-fabric-react/lib/Link'; +import { LayerHost } from 'office-ui-fabric-react/lib/Layer'; +import { + ExampleCard, + ComponentPage, + PropertiesTableSet +} from '@uifabric/example-app-base'; +import { OverflowSetCustomExample } from './examples/OverflowSet.Custom.Example'; +import { OverflowSetBasicExample } from './examples/OverflowSet.Basic.Example'; + +const OverflowSetCustomExampleCode = require('!raw-loader!office-ui-fabric-react/src/components/OverflowSet/examples/OverflowSet.Custom.Example.tsx') as string; +const OverflowSetBasicExampleCode = require('!raw-loader!office-ui-fabric-react/src/components/OverflowSet/examples/OverflowSet.Basic.Example.tsx') as string; + +export class OverflowSetPage extends React.Component { + public render() { + return ( + +

+ The OverflowSet is a flexible container component that is useful for displaying a primary set of content with additional content in an overflow callout. + Note that the example below is only an example of how to render the component, not a specific use case. +

+ + } + exampleCards={ + + + + + + + + + } + propertiesTables={ + ('!raw-loader!office-ui-fabric-react/src/components/OverflowSet/OverflowSet.Props.ts') + ] } + /> + } + /> + ); + } +} diff --git a/packages/office-ui-fabric-react/src/components/OverflowSet/examples/OverflowSet.Basic.Example.tsx b/packages/office-ui-fabric-react/src/components/OverflowSet/examples/OverflowSet.Basic.Example.tsx new file mode 100644 index 0000000000000..3509f4bd91288 --- /dev/null +++ b/packages/office-ui-fabric-react/src/components/OverflowSet/examples/OverflowSet.Basic.Example.tsx @@ -0,0 +1,71 @@ +/* tslint:disable:no-unused-variable */ +import * as React from 'react'; +/* tslint:enable:no-unused-variable */ +import { BaseComponent, css } from 'office-ui-fabric-react/lib/Utilities'; +import { IconButton } from 'office-ui-fabric-react/lib/Button'; +import { Link } from 'office-ui-fabric-react/lib/Link'; +import { + OverflowSet +} from 'office-ui-fabric-react/lib/OverflowSet'; + +import * as stylesImport from './OverflowSet.Example.scss'; +const styles: any = stylesImport; + +export class OverflowSetBasicExample extends BaseComponent { + + public render() { + return ( + { return; }, + }, + { + key: 'item2', + name: 'Link 2', + onClick: () => { return; }, + }, + { + key: 'item3', + name: 'Link 3', + onClick: () => { return; } + } + ] } + overflowItems={ [ + { + key: 'item4', + name: 'Overflow Link 1', + onClick: () => { return; } + }, + { + key: 'item5', + name: 'Overflow Link 2', + onClick: () => { return; } + } + ] + } + onRenderOverflowButton={ (buttonProps) => { + return ( + + ); + } } + onRenderItem={ (item) => { + return ( + { item.name } + ); + } } + /> + ); + } +} \ No newline at end of file diff --git a/packages/office-ui-fabric-react/src/components/OverflowSet/examples/OverflowSet.Custom.Example.tsx b/packages/office-ui-fabric-react/src/components/OverflowSet/examples/OverflowSet.Custom.Example.tsx new file mode 100644 index 0000000000000..c602b045a5ed7 --- /dev/null +++ b/packages/office-ui-fabric-react/src/components/OverflowSet/examples/OverflowSet.Custom.Example.tsx @@ -0,0 +1,140 @@ +/* tslint:disable:no-unused-variable */ +import * as React from 'react'; +/* tslint:enable:no-unused-variable */ +import { BaseComponent, css } from 'office-ui-fabric-react/lib/Utilities'; +import { DefaultButton } from 'office-ui-fabric-react/lib/Button'; +import { SearchBox } from 'office-ui-fabric-react/lib/SearchBox'; +import { + OverflowSet +} from 'office-ui-fabric-react/lib/OverflowSet'; + +import * as stylesImport from './OverflowSet.Example.scss'; +const styles: any = stylesImport; + +export class OverflowSetCustomExample extends BaseComponent { + + public render() { + return ( + { + return ( + + ); + } + }, + { + key: 'newItem', + name: 'New', + icon: 'Add', + ariaLabel: 'New. Use left and right arrow keys to navigate', + onClick: () => { return; }, + subMenuProps: { + items: [ + { + key: 'emailMessage', + name: 'Email message', + icon: 'Mail', + }, + { + key: 'calendarEvent', + name: 'Calendar event', + icon: 'Calendar' + } + ], + }, + }, + { + key: 'upload', + name: 'Upload', + icon: 'Upload', + onClick: () => { return; }, + }, + { + key: 'share', + name: 'Share', + icon: 'Share', + onClick: () => { return; } + } + ] } + overflowItems={ [ + { + key: 'newItem', + name: 'Add', + icon: 'Add', + ariaLabel: 'New. Use left and right arrow keys to navigate', + onClick: () => { return; }, + subMenuProps: { + items: [ + { + key: 'emailMessage', + name: 'Email message', + icon: 'Mail', + }, + { + key: 'calendarEvent', + name: 'Calendar event', + icon: 'Calendar' + } + ], + }, + }, + { + key: 'move', + name: 'Move to...', + icon: 'MoveToFolder', + onClick: () => { return; } + }, + { + key: 'copy', + name: 'Copy to...', + icon: 'Copy', + onClick: () => { return; } + }, + { + key: 'rename', + name: 'Rename...', + icon: 'Edit', + onClick: () => { return; } + }, + { + key: 'disabled', + name: 'Disabled...', + icon: 'Cancel', + disabled: true, + onClick: () => { return; } + } + ] + } + onRenderOverflowButton={ (buttonProps) => { + return ( + + ); + } } + onRenderItem={ (item) => { + if (item.onRender) { + return ( + item.onRender(item) + ); + } + return ( + + ); + } } + /> + ); + } +} \ No newline at end of file diff --git a/packages/office-ui-fabric-react/src/components/OverflowSet/examples/OverflowSet.Example.scss b/packages/office-ui-fabric-react/src/components/OverflowSet/examples/OverflowSet.Example.scss new file mode 100644 index 0000000000000..e1d44f19f1970 --- /dev/null +++ b/packages/office-ui-fabric-react/src/components/OverflowSet/examples/OverflowSet.Example.scss @@ -0,0 +1,39 @@ +@import '../../../common/common'; + + +:global { + .ms-OverflowSet .ms-SearchBox { + margin-bottom: 0; + width: 200px; + } +} + +.overflowLinks { + @include margin-right(10px); +} + +.overflowButton { + min-width: 0; + padding: 0 4px; + align-self: stretch; + height: auto; +} + +.isEnabled { + &.isOpened { + &:hover { + background-color: $ms-color-neutralQuaternaryAlt; + color: $ms-color-black; + } + } + + &:hover, &.isOpened { + color: $ms-color-neutralDark; + background-color: $ms-color-neutralLight; + } + + &:active { + background-color: $ms-color-neutralQuaternaryAlt; + color: $ms-color-black; + } +} diff --git a/packages/office-ui-fabric-react/src/components/OverflowSet/index.ts b/packages/office-ui-fabric-react/src/components/OverflowSet/index.ts new file mode 100644 index 0000000000000..24d67e9dadc93 --- /dev/null +++ b/packages/office-ui-fabric-react/src/components/OverflowSet/index.ts @@ -0,0 +1,2 @@ +export * from './OverflowSet'; +export * from './OverflowSet.Props'; diff --git a/packages/office-ui-fabric-react/src/demo/AppDefinition.tsx b/packages/office-ui-fabric-react/src/demo/AppDefinition.tsx index dfdaa7455f6cf..b6014a63f0898 100644 --- a/packages/office-ui-fabric-react/src/demo/AppDefinition.tsx +++ b/packages/office-ui-fabric-react/src/demo/AppDefinition.tsx @@ -142,6 +142,12 @@ export const AppDefinition: IAppDefinition = { name: 'Overlay', url: '#/examples/overlay' }, + { + getComponent: cb => cb(require('../components/OverflowSet/OverflowSetPage').OverflowSetPage), + key: 'OverflowSet', + name: 'OverflowSet', + url: '#/examples/overflowset' + }, { getComponent: cb => cb(require('../components/Panel/PanelPage').PanelPage), key: 'Panel',