-
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 36 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 |
|---|---|---|
| @@ -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 |
|---|---|---|
|
|
@@ -35,6 +35,11 @@ export interface IButtonProps extends React.HTMLAttributes<HTMLButtonElement | H | |
| */ | ||
| className?: string; | ||
|
|
||
| /** | ||
| * If provided, additional class name to provide on the root element. | ||
| */ | ||
| classNames?: IButtonClassNames; | ||
|
|
||
| /** | ||
| * The aria label of the button for the benefit of screen readers. | ||
| */ | ||
|
|
@@ -154,3 +159,17 @@ export enum ButtonType { | |
| icon = 5, | ||
| default = 6 | ||
| } | ||
|
|
||
| export interface IButtonClassNames { | ||
| base?: string; | ||
|
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. We should add some comments here saying what the class names correspond to so that consumers know what class names to override when customizing button styles |
||
| variant?: string; | ||
| isDisabled?: string; | ||
| isEnabled?: string; | ||
| isOpened?: string; | ||
| description?: string; | ||
| flexContainer?: string; | ||
| icon?: string; | ||
| menuIcon?: string; | ||
| label?: string; | ||
| root?: string; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| import * as React from 'react'; | ||
| import { BaseButton, IButtonClassNames } from '../BaseButton'; | ||
| import { BaseComponent, nullRender } from '../../../Utilities'; | ||
| import { IButtonProps } from '../Button.Props'; | ||
| import { BaseButton } from '../BaseButton'; | ||
| import { BaseComponent, nullRender, assign } from '../../../Utilities'; | ||
| import { IButtonProps, IButtonClassNames } from '../Button.Props'; | ||
| import * as stylesImport from './CommandButton.scss'; | ||
| const styles: any = stylesImport; | ||
|
|
||
|
|
@@ -12,6 +12,7 @@ const CLASS_NAMES: IButtonClassNames = { | |
| menuIcon: styles.icon, | ||
| isDisabled: styles.isDisabled, | ||
| isEnabled: styles.isEnabled, | ||
| isOpened: styles.isOpened, | ||
| label: styles.label, | ||
| root: styles.root, | ||
| flexContainer: styles.flexContainer | ||
|
|
@@ -27,9 +28,10 @@ export class CommandButton extends BaseComponent<IButtonProps, {}> { | |
| public render() { | ||
| return ( | ||
| <BaseButton | ||
| classNames={ CLASS_NAMES } | ||
| { ...this.props } | ||
| classNames={ assign({}, CLASS_NAMES, this.props.classNames) } | ||
|
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. Can we use the spread operator here instead of assign?
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 assign is to allow prop classnames to override the button specific class names. i.e. I want a new .isEnabled:hover style, I can override their isEnabled with my own. And since it's css modules, even if I use the same isEnabled class name, the hash will be different.
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. That should still work with object spread though. They are equivalent and is more compact: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html It would be something like this classNames = { ...CLASS_NAMES, ..this.props.classNames }
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. Pulled this out. @dzearing is doing this using glamor, and yes, spreads. |
||
| onRenderDescription={ nullRender } | ||
| { ...this.props } /> | ||
| /> | ||
| ); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,7 +32,7 @@ | |
|
|
||
| .isEnabled { | ||
|
|
||
| &:hover { | ||
| &:hover, &.isOpened { | ||
| background-color: $ms-color-themeDark; | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import * as React from 'react'; | ||
| import { OverflowSet } from './OverflowSet'; | ||
| import { IContextualMenuItem } from '../../ContextualMenu'; | ||
| import { IButtonProps } from '../../Button'; | ||
| import { IRenderFunction } from '../../Utilities'; | ||
|
|
||
| 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[]; | ||
|
|
||
| /** | ||
| * 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,45 @@ | ||
| 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) => { | ||
| return ( | ||
| <div key={ i } className={ css('ms-OverflowSet-item', styles.item) }> | ||
|
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. This isn't a great way to assign keys since it wouldn't let React's reconciler detect reorderings and insertions/deletions. More details can be found here https://facebook.github.io/react/docs/lists-and-keys.html Can we provide a way for the consumer to pass in a unique identifier for each item?
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 think I originally had that in the map. Let me put it back in. Look for a key and fall back to i if there is no key. |
||
| { this.props.onRenderItem(item) } | ||
| </div> | ||
| ); | ||
| }); | ||
| } | ||
| } | ||
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 just realized this is a really bad contract; for example, it is unclear from a user how to define the color on an icon that is disabled. We need to tweak this a bit.
Can we hold off adding something that would be deprecated fast just for a sec? Sorry, know this has been a long time.
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.
So no exposing of the IButtonClassNames or any of that? Revert all the changes on the button files?