-
Notifications
You must be signed in to change notification settings - Fork 2.9k
BaseExtendedPicker: Create contextmenu for renderedItem, fix auto focus #3954
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
Changes from all commits
5f44016
6eaa7b8
56429ea
825e429
4367ed6
d3eb702
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,11 @@ | ||
| { | ||
| "changes": [ | ||
| { | ||
| "packageName": "@uifabric/experiments", | ||
| "comment": "BaseExtendedPicker: Create component to wrap the rendered item, so users get contextual menu if certain props are present, get rid of loading state, fix autofocus on input after suggestion selection", | ||
| "type": "minor" | ||
| } | ||
| ], | ||
| "packageName": "@uifabric/experiments", | ||
| "email": "amyngu@microsoft.com" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,13 @@ | ||
| .editingInput { | ||
| border: 0px; | ||
| outline: none; | ||
| width: 100%; | ||
|
|
||
| &::-ms-clear { | ||
| display: none; | ||
| } | ||
| } | ||
|
|
||
| .editingContainer { | ||
| margin: 4px; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| /* tslint:disable */ | ||
| import * as React from 'react'; | ||
| /* tslint:enable */ | ||
| import { BaseComponent, autobind } from '../../../../Utilities'; | ||
| import { IExtendedPersonaProps } from '../SelectedPeopleList'; | ||
| import { ContextualMenu, DirectionalHint } from 'office-ui-fabric-react/lib/ContextualMenu'; | ||
| import { IContextualMenuItem } from 'office-ui-fabric-react/lib/ContextualMenu'; | ||
| import { IBaseProps } from 'office-ui-fabric-react/lib/Utilities'; | ||
|
|
||
| export interface IPeoplePickerItemState { | ||
| contextualMenuVisible: boolean; | ||
| } | ||
|
|
||
| export interface ISelectedItemWithContextMenuProps extends IBaseProps { | ||
| renderedItem: JSX.Element; | ||
| beginEditing?: (item: IExtendedPersonaProps) => void; | ||
| menuItems: IContextualMenuItem[]; | ||
| item: IExtendedPersonaProps; | ||
| } | ||
|
|
||
| export class SelectedItemWithContextMenu extends BaseComponent<ISelectedItemWithContextMenuProps, IPeoplePickerItemState> { | ||
| protected itemElement: HTMLElement; | ||
|
|
||
| constructor(props: ISelectedItemWithContextMenuProps) { | ||
| super(props); | ||
| this.state = { contextualMenuVisible: false }; | ||
| } | ||
|
|
||
| public render(): JSX.Element { | ||
| return ( | ||
| <div | ||
| ref={ this._resolveRef('itemElement') } | ||
| onContextMenu={ this._onClick } | ||
| > | ||
| { this.props.renderedItem } | ||
| { this.state.contextualMenuVisible ? ( | ||
| <ContextualMenu | ||
| items={ this.props.menuItems } | ||
| shouldFocusOnMount={ true } | ||
| target={ this.itemElement } | ||
| onDismiss={ this._onCloseContextualMenu } | ||
| directionalHint={ DirectionalHint.bottomLeftEdge } | ||
| />) | ||
| : null | ||
| } | ||
| </div >); | ||
| } | ||
|
|
||
| @autobind | ||
| private _onClick(ev: React.MouseEvent<HTMLElement>): void { | ||
| ev.preventDefault(); | ||
| if (this.props.beginEditing && !this.props.item.isValid) { | ||
| this.props.beginEditing(this.props.item); | ||
| } else { | ||
| this.setState({ contextualMenuVisible: true }); | ||
| } | ||
| } | ||
|
|
||
| @autobind | ||
| private _onCloseContextualMenu(ev: Event): void { | ||
| this.setState({ contextualMenuVisible: false }); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ import { BaseSelectedItemsList } from '../BaseSelectedItemsList'; | |
| import { IBaseSelectedItemsListProps, ISelectedItemProps } from '../BaseSelectedItemsList.types'; | ||
| import { IPersonaProps } from 'office-ui-fabric-react/lib/Persona'; | ||
| import { ExtendedSelectedItem } from './Items/ExtendedSelectedItem'; | ||
| import { SelectedItemWithContextMenu } from './Items/SelectedItemWithContextMenu'; | ||
| import { autobind, IRenderFunction } from '../../../Utilities'; | ||
| import { IContextualMenuItem } from 'office-ui-fabric-react/lib/ContextualMenu'; | ||
| import { IBaseFloatingPickerProps } from '../../../FloatingPicker'; | ||
|
|
@@ -20,7 +21,6 @@ export interface IExtendedPersonaProps extends IPersonaProps { | |
|
|
||
| export interface ISelectedPeopleItemProps extends ISelectedItemProps<IExtendedPersonaProps> { | ||
| onExpandItem?: () => void; | ||
| menuItems: IContextualMenuItem[]; | ||
| renderPersonaCoin?: IRenderFunction<IPersonaProps>; | ||
| renderPrimaryText?: IRenderFunction<IPersonaProps>; | ||
| } | ||
|
|
@@ -93,10 +93,28 @@ export class SelectedPeopleList extends BasePeopleSelectedItemsList { | |
| ); | ||
| } else { | ||
| let onRenderItem = this.props.onRenderItem as (props: ISelectedPeopleItemProps) => JSX.Element; | ||
| return onRenderItem({ ...props }); | ||
| let renderedItem = onRenderItem(props); | ||
| return ( | ||
| props.menuItems.length > 0 ? | ||
| ( | ||
| <SelectedItemWithContextMenu | ||
| renderedItem={ renderedItem } | ||
| beginEditing={ this._beginEditing } | ||
| menuItems={ this._createMenuItems(props.item) } | ||
| item={ props.item } | ||
| /> | ||
| ) | ||
| : renderedItem | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| @autobind | ||
| private _beginEditing(item: IExtendedPersonaProps): void { | ||
|
Contributor
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 use begin and complete editing? You should be able to pass a dismiss function to contextualmenu that will handle some of this.
Contributor
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 contextual menu will not be open throughout the duration of this, so I don't think using this dismiss function is correct here. |
||
| item.isEditing = true; | ||
| this.forceUpdate(); | ||
| } | ||
|
|
||
| @autobind | ||
| // tslint:disable-next-line:no-any | ||
| private _completeEditing(oldItem: any, newItem: any): void { | ||
|
|
@@ -111,35 +129,38 @@ export class SelectedPeopleList extends BasePeopleSelectedItemsList { | |
| if (this.props.editMenuItemText && this.props.getEditingItemText) { | ||
| menuItems.push({ | ||
| key: 'Edit', | ||
| name: this.props.editMenuItemText ? this.props.editMenuItemText : 'Edit', | ||
| name: this.props.editMenuItemText, | ||
| onClick: (ev: React.MouseEvent<HTMLElement>, menuItem: IContextualMenuItem) => { | ||
| (menuItem.data as IExtendedPersonaProps).isEditing = true; | ||
| this.forceUpdate(); | ||
| this._beginEditing(menuItem.data); | ||
| }, | ||
| data: item, | ||
| }); | ||
| } | ||
|
|
||
| menuItems.push( | ||
| { | ||
| key: 'Remove', | ||
| name: this.props.removeMenuItemText ? this.props.removeMenuItemText : 'Remove', | ||
| onClick: (ev: React.MouseEvent<HTMLElement>, menuItem: IContextualMenuItem) => { | ||
| this.removeItem(menuItem.data as ISelectedItemProps<IExtendedPersonaProps>); | ||
| }, | ||
| data: item, | ||
| }, | ||
| { | ||
| if (this.props.removeMenuItemText) { | ||
| menuItems.push( | ||
| { | ||
| key: 'Remove', | ||
| name: this.props.removeMenuItemText, | ||
| onClick: (ev: React.MouseEvent<HTMLElement>, menuItem: IContextualMenuItem) => { | ||
| this.removeItem(menuItem.data as ISelectedItemProps<IExtendedPersonaProps>); | ||
| }, | ||
| data: item, | ||
| }); | ||
| } | ||
|
|
||
| if (this.props.copyMenuItemText) { | ||
| menuItems.push({ | ||
| key: 'Copy', | ||
| name: this.props.copyMenuItemText ? this.props.copyMenuItemText : 'Copy', | ||
| name: this.props.copyMenuItemText, | ||
| onClick: (ev: React.MouseEvent<HTMLElement>, menuItem: IContextualMenuItem) => { | ||
| if (this.props.onCopyItems) { | ||
| (this.copyItems as (items: IExtendedPersonaProps[]) => void)([menuItem.data] as IExtendedPersonaProps[]); | ||
| } | ||
| }, | ||
| data: item, | ||
| }, | ||
| ); | ||
| }); | ||
| } | ||
|
|
||
| return menuItems; | ||
| } | ||
|
|
||
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.
This almost feels too specific, could you style a button with contextualmenuitems to meet your needs?
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.
You're right. I will revisit this and try and create a better abstraction to fit my needs