-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Overflow set #1537
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Overflow set #1537
Changes from all commits
a8e4cc3
7345c8c
c3ff083
62a5469
eb237c8
9de2ec2
d54c5c6
228ddd1
cd011db
1085601
850c74a
8155ef5
e296f1a
e8e30c0
458ad1f
c81f76e
ac1cb5e
b526d40
7e74eef
fe718e3
6d9fd0f
a887b22
82a4188
2eab455
fd424b4
8f35a16
8d7bc00
e7b86db
82c5b6d
988e0c7
c0884d9
198e3ae
2520d1d
d9ba936
d57593a
ac26ad3
e8eff9c
473c484
78275f9
35f9325
bb54cbd
e8c2960
6d424e3
038b3f7
edb0ec5
a72004f
30c1a74
501956d
8f64dec
2e4df29
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,3 +8,4 @@ | |
| ], | ||
| "email": "micahgodbolt@gmail.com" | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export * from './components/OverflowSet/index'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<OverflowSet> { | ||
|
|
||
| /** | ||
| * 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[]; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are the types different items vs overflow items?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OverflowItems are meant to be rendered in a contextual menu. Of course there isn't anything stopping someone from rendering them in something else....If any[] is prefered I have no problems either way.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think contextualmenuitem already has a mechanism to render anything else inside them, so I think it is ok. |
||
|
|
||
| /** | ||
| * Method to call when trying to render an item. | ||
| */ | ||
| onRenderItem: IRenderFunction<any>; | ||
|
|
||
| /** | ||
| * Rendering method for overflow button and contextual menu. | ||
| */ | ||
| onRenderOverflowButton: IRenderFunction<IButtonProps>; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a little unsure about this API. We definitely want to be able to provide flexibility for rendering the overflow button, but it seems like we would have an onRenderMenuItem function for handling items in the contextual menu
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The rendering of the menu items is already handled by the contextual menu. and in fact IContextualMenuItem can accept an onRender function already.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah I see. I guess I was expecting the API to list "top level controls" and "overflow controls" in a similar manner. But given the existing mechanism for overriding menu items in contextualmenuitem, this seems to make sense and also allows customization of the button itself. |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| @import '../../common/common'; | ||
|
|
||
| .root { | ||
| position: relative; | ||
| display: flex; | ||
| flex-wrap: nowrap; | ||
| } | ||
|
|
||
| .item { | ||
| flex-shrink: 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<IOverflowSetProps, null> { | ||
|
|
||
| public render() { | ||
| let { | ||
| items, | ||
| overflowItems, | ||
| onRenderOverflowButton | ||
| } = this.props; | ||
|
|
||
| const overflowButtonProps: IButtonProps = { | ||
| menuProps: { items: overflowItems } | ||
| }; | ||
|
|
||
| return ( | ||
| <FocusZone className={ css('ms-OverflowSet', styles.root) } direction={ FocusZoneDirection.horizontal } role='menubar' > | ||
| { items && this._onRenderItems(items) } | ||
| { overflowItems.length && onRenderOverflowButton(overflowButtonProps) } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No default value here?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you mean by default value?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the onrenderoverflowbutton? I guess it makes sense given your other comment regarding how overflow items are rendered.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, i had a default button at one time, but what does the button look like? Hover/active/selected? I'm expecting each user will customize the button to their use case. A default button wouldn't serve much purpose unless we determined what the default usecase was.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems reasonable, we can add it later if there is a "common" button that arises |
||
| </FocusZone> | ||
| ); | ||
| } | ||
|
|
||
| @autobind | ||
| private _onRenderItems(items: any[]): JSX.Element[] { | ||
| return items.map((item, i) => { | ||
| let key = item.key ? item.key : i; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The props definition should say that items can take a key. It might even be worth explicitly stating this in the type definition instead of just putting any (though not sure how to best do that, maybe an intersection type?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can do this in the prop
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if this really solves it though. Basically it's either anything, or just a key. Unless I don't understand intersection properly.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You actually probably don't need an intersection, you can just say items?: {key?: string} []. You can assign anything to that.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| return ( | ||
| <div key={ key } className={ css('ms-OverflowSet-item', styles.item) }> | ||
| { this.props.onRenderItem(item) } | ||
| </div> | ||
| ); | ||
| }); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<any, any> { | ||
| public render() { | ||
| return ( | ||
| <ComponentPage | ||
| title='OverflowSet' | ||
| componentName='OverflowSetExample' | ||
| overview={ | ||
| <div> | ||
| <p> | ||
| 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. | ||
| </p> | ||
| </div> | ||
| } | ||
| exampleCards={ | ||
| <LayerHost> | ||
| <ExampleCard title='OverflowSet Basic Example' code={ OverflowSetBasicExampleCode }> | ||
| <OverflowSetBasicExample /> | ||
| </ExampleCard> | ||
| <ExampleCard title='OverflowSet Custom Example' code={ OverflowSetCustomExampleCode }> | ||
| <OverflowSetCustomExample /> | ||
| </ExampleCard> | ||
| </LayerHost> | ||
| } | ||
| propertiesTables={ | ||
| <PropertiesTableSet | ||
| sources={ [ | ||
| require<string>('!raw-loader!office-ui-fabric-react/src/components/OverflowSet/OverflowSet.Props.ts') | ||
| ] } | ||
| /> | ||
| } | ||
| /> | ||
| ); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<any, any> { | ||
|
|
||
| public render() { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe you should keep the basic example basic and have a "customized" example to customized. Reading the docs this is basically a for loop on items to render them as a given thing, with a menuProps.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is done |
||
| return ( | ||
| <OverflowSet | ||
| items={ [ | ||
| { | ||
| key: 'item1', | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How come these aren't being used in the overflow set?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
| name: 'Link 1', | ||
| ariaLabel: 'New. Use left and right arrow keys to navigate', | ||
| onClick: () => { 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 ( | ||
| <IconButton | ||
| className={ css(styles.overflowButton) } | ||
| iconProps={ { iconName: 'More' } } | ||
| menuIconProps={ null } | ||
| menuProps={ buttonProps.menuProps } | ||
| /> | ||
| ); | ||
| } } | ||
| onRenderItem={ (item) => { | ||
| return ( | ||
| <Link | ||
| className={ css(styles.overflowLinks) } | ||
| onClick={ item.onClick } | ||
| >{ item.name }</Link> | ||
| ); | ||
| } } | ||
| /> | ||
| ); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<any, any> { | ||
|
|
||
| public render() { | ||
| return ( | ||
| <OverflowSet | ||
| items={ [ | ||
| { | ||
| key: 'search', | ||
| 'onRender': (item) => { | ||
| return ( | ||
| <SearchBox | ||
| labelText='Search' | ||
| /> | ||
| ); | ||
| } | ||
| }, | ||
| { | ||
| 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 ( | ||
| <DefaultButton | ||
| className={ css(styles.overflowButton) } | ||
| iconProps={ { iconName: 'More' } } | ||
| menuIconProps={ null } | ||
| menuProps={ buttonProps.menuProps } | ||
| /> | ||
| ); | ||
| } } | ||
| onRenderItem={ (item) => { | ||
| if (item.onRender) { | ||
| return ( | ||
| item.onRender(item) | ||
| ); | ||
| } | ||
| return ( | ||
| <DefaultButton | ||
| iconProps={ { iconName: item.icon } } | ||
| menuProps={ item.subMenuProps } | ||
| text={ item.name } | ||
| > </DefaultButton> | ||
| ); | ||
| } } | ||
| /> | ||
| ); | ||
| } | ||
| } |

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think all you want here is { id? : string}[]