Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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/experiments",
"comment": "Use new \"use current input\" command in Suggestions",
"type": "minor"
}
],
"packageName": "@uifabric/experiments",
"email": "[email protected]"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "office-ui-fabric-react",
"comment": "Add \"use current input command\" and remove need to explicity call focus when moving between suggestions and commands",
"type": "minor"
}
],
"packageName": "office-ui-fabric-react",
"email": "[email protected]"
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,12 @@ export interface IPeoplePickerExampleState {
mostRecentlyUsed: IPersonaProps[];
}

const suggestionProps: IBasePickerSuggestionsProps = {
suggestionsHeaderText: 'Suggested People',
mostRecentlyUsedHeaderText: 'Suggested Contacts',
noResultsFoundText: 'No results found',
loadingText: 'Loading',
showRemoveButtons: true,
suggestionsAvailableAlertText: 'People Picker Suggestions available',
suggestionsContainerAriaLabel: 'Suggested contacts',
searchForMoreText: 'Search more',
};

// tslint:disable-next-line:no-any
export class ExtendedPeoplePickerTypesExample extends BaseComponent<{}, IPeoplePickerExampleState> {
private _picker: ExtendedPeoplePicker;
private _floatingPickerProps: IBaseFloatingPickerProps<IPersonaProps>;
private _selectedItemsListProps: ISelectedPeopleProps;
private _suggestionProps: IBasePickerSuggestionsProps;

constructor(props: {}) {
super(props);
Expand All @@ -54,15 +44,28 @@ export class ExtendedPeoplePickerTypesExample extends BaseComponent<{}, IPeopleP
mostRecentlyUsed: mru,
};

this._suggestionProps = {
suggestionsHeaderText: 'Suggested People',
mostRecentlyUsedHeaderText: 'Suggested Contacts',
noResultsFoundText: 'No results found',
loadingText: 'Loading',
showRemoveButtons: true,
suggestionsAvailableAlertText: 'People Picker Suggestions available',
suggestionsContainerAriaLabel: 'Suggested contacts',
searchForMoreText: 'Search more',
forceResolveText: 'Use this name',
};

this._floatingPickerProps = {
suggestionsController: new SuggestionsController<IPersonaProps>(),
onResolveSuggestions: this._onFilterChanged,
getTextFromItem: this._getTextFromItem,
pickerSuggestionsProps: suggestionProps,
pickerSuggestionsProps: this._suggestionProps,
key: 'normal',
onRemoveSuggestion: this._onRemoveSuggestion,
onValidateInput: this._validateInput,
onZeroQuerySuggestion: this._returnMostRecentlyUsed,
showForceResolve: this._shouldShowForceResolve,
};

this._selectedItemsListProps = {
Expand Down Expand Up @@ -193,6 +196,12 @@ export class ExtendedPeoplePickerTypesExample extends BaseComponent<{}, IPeopleP
return copyText;
}

@autobind
private _shouldShowForceResolve(): boolean {
return this._validateInput(this._picker.floatingPicker.inputText)
&& this._picker.floatingPicker.suggestions.length === 0;
}

private _listContainsPersona(persona: IPersonaProps, personas: IPersonaProps[]): boolean {
if (!personas || !personas.length || personas.length === 0) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ export class BaseFloatingPicker<T, P extends IBaseFloatingPickerProps<T>> extend
};
}

public get inputText(): string {
return this.state.queryString;
}

// tslint:disable-next-line:no-any
public get suggestions(): any[] {
return this.suggestionStore.suggestions;
}

public forceResolveSuggestion(): void {
if (this.suggestionStore.hasSelectedSuggestion()) {
this.completeSuggestion();
Expand Down Expand Up @@ -87,7 +96,6 @@ export class BaseFloatingPicker<T, P extends IBaseFloatingPickerProps<T>> extend
this.setState({
suggestionsVisible: false,
});
console.log('hidepicker');
}

public showPicker(): void {
Expand Down Expand Up @@ -129,12 +137,14 @@ export class BaseFloatingPicker<T, P extends IBaseFloatingPickerProps<T>> extend

@autobind
public refocusSuggestions(keyCode: KeyCodes): void {
if (keyCode === KeyCodes.up) {
this.suggestionStore.setSelectedSuggestion(
this.suggestionStore.suggestions.length - 1
);
} else if (keyCode === KeyCodes.down) {
this.suggestionStore.setSelectedSuggestion(0);
if (this.suggestionStore.suggestions && this.suggestionStore.suggestions.length > 0) {
if (keyCode === KeyCodes.up) {
this.suggestionStore.setSelectedSuggestion(
this.suggestionStore.suggestions.length - 1
);
} else if (keyCode === KeyCodes.down) {
this.suggestionStore.setSelectedSuggestion(0);
}
}
}

Expand Down Expand Up @@ -169,6 +179,8 @@ export class BaseFloatingPicker<T, P extends IBaseFloatingPickerProps<T>> extend
calloutWidth={ this.props.calloutWidth ? this.props.calloutWidth : 0 }
>
<TypedSuggestion
showForceResolve={ this._showForceResolve }
createGenericItem={ this._onValidateInput }
onRenderSuggestion={ this.props.onRenderSuggestionsItem }
onSuggestionClick={ this.onSuggestionClick }
onSuggestionRemove={ this.onSuggestionRemove }
Expand Down Expand Up @@ -341,7 +353,8 @@ export class BaseFloatingPicker<T, P extends IBaseFloatingPickerProps<T>> extend
!(this.props.inputElement as HTMLElement).contains(ev.target as HTMLElement))) {
return;
}
switch (ev.which) {
let keyCode = ev.which;
switch (keyCode) {
case KeyCodes.escape:
this.setState({ suggestionsVisible: false });
ev.preventDefault();
Expand All @@ -350,8 +363,9 @@ export class BaseFloatingPicker<T, P extends IBaseFloatingPickerProps<T>> extend

case KeyCodes.tab:
case KeyCodes.enter:
if (
!ev.shiftKey &&
if (this.suggestionElement.hasSuggestedActionSelected()) {
this.suggestionElement.executeSelectedAction();
} else if (!ev.shiftKey &&
!ev.ctrlKey &&
this.suggestionStore.hasSelectedSuggestion()) {
this.completeSuggestion();
Expand All @@ -378,38 +392,49 @@ export class BaseFloatingPicker<T, P extends IBaseFloatingPickerProps<T>> extend
break;

case KeyCodes.up:
if (
this.state.moreSuggestionsAvailable &&
this.suggestionElement.props.searchForMoreText &&
this.suggestionStore.currentIndex === 0
) {
this.suggestionElement.focusSearchForMoreButton();
this.suggestionStore.deselectAllSuggestions();
this.forceUpdate();
if (this.suggestionElement.tryHandleKeyDown(keyCode, this.suggestionStore.currentIndex)) {
ev.preventDefault();
ev.stopPropagation();
} else {
if (this.suggestionStore.previousSuggestion()) {
if (this.suggestionElement.hasSuggestedAction() &&
this.suggestionStore.currentIndex === 0
) {
ev.preventDefault();
ev.stopPropagation();
this.onSuggestionSelect();
this.suggestionElement.focusAboveSuggestions();
this.suggestionStore.deselectAllSuggestions();
this.forceUpdate();
} else {
if (this.suggestionStore.previousSuggestion()) {
ev.preventDefault();
ev.stopPropagation();
this.onSuggestionSelect();
}
}
}
break;

case KeyCodes.down:
if (
this.state.moreSuggestionsAvailable &&
this.suggestionElement.props.searchForMoreText &&
this.suggestionStore.currentIndex + 1 ===
this.suggestionStore.suggestions.length
) {
this.suggestionElement.focusSearchForMoreButton();
this.suggestionStore.deselectAllSuggestions();
this.forceUpdate();
if (this.suggestionElement.tryHandleKeyDown(keyCode, this.suggestionStore.currentIndex)) {
ev.preventDefault();
ev.stopPropagation();
} else {
if (this.suggestionStore.nextSuggestion()) {
if (
this.suggestionElement.hasSuggestedAction() &&
this.suggestionStore.currentIndex + 1 ===
this.suggestionStore.suggestions.length
) {
ev.preventDefault();
ev.stopPropagation();
this.onSuggestionSelect();
this.suggestionElement.focusBelowSuggestions();
this.suggestionStore.deselectAllSuggestions();
this.forceUpdate();
} else {
if (this.suggestionStore.nextSuggestion()) {
ev.preventDefault();
ev.stopPropagation();
this.onSuggestionSelect();
}
}
}
break;
Expand Down Expand Up @@ -463,10 +488,10 @@ export class BaseFloatingPicker<T, P extends IBaseFloatingPickerProps<T>> extend
this.updateSuggestionsList(suggestions, updatedValue);
}

@autobind
private _onValidateInput(): void {
if (
this.props.onValidateInput &&
(this.props.onValidateInput as ((input: string) => boolean))(this.state.queryString) !== true &&
this.props.createGenericItem
) {
let itemToConvert = (this.props.createGenericItem as ((
Expand All @@ -481,6 +506,11 @@ export class BaseFloatingPicker<T, P extends IBaseFloatingPickerProps<T>> extend
}
}

@autobind
private _showForceResolve(): boolean {
return this.props.showForceResolve ? this.props.showForceResolve() : false;
}

private _getTextFromItem(item: T, currentValue?: string): string {
if (this.props.getTextFromItem) {
return (this.props.getTextFromItem as ((item: T, currentValue?: string) => string))(item, currentValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ export interface IBaseFloatingPickerProps<T> extends React.Props<any> {
isValid: boolean
) => ISuggestionModel<T>;

/**
* The callback that should be called to see if the force resolve command should be shown
*/
showForceResolve?: () => boolean;

/**
* The items that the base picker should currently display as selected. If this is provided then the picker will act as a controlled
* component.
Expand All @@ -113,4 +118,4 @@ export interface IBaseFloatingPickerProps<T> extends React.Props<any> {
* Width for the suggestions callout
*/
calloutWidth?: number;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,12 @@ export class BasePicker<T, P extends IBasePickerProps<T>> extends BaseComponent<
@autobind
public refocusSuggestions(keyCode: KeyCodes) {
this.resetFocus();
if (keyCode === KeyCodes.up) {
this.suggestionStore.setSelectedSuggestion(this.suggestionStore.suggestions.length - 1);
} else if (keyCode === KeyCodes.down) {
this.suggestionStore.setSelectedSuggestion(0);
if (this.suggestionStore.suggestions && this.suggestionStore.suggestions.length > 0) {
if (keyCode === KeyCodes.up) {
this.suggestionStore.setSelectedSuggestion(this.suggestionStore.suggestions.length - 1);
} else if (keyCode === KeyCodes.down) {
this.suggestionStore.setSelectedSuggestion(0);
}
}
}

Expand Down Expand Up @@ -443,7 +445,8 @@ export class BasePicker<T, P extends IBasePickerProps<T>> extends BaseComponent<

@autobind
protected onKeyDown(ev: React.KeyboardEvent<HTMLElement>) {
switch (ev.which) {
let keyCode = ev.which;
switch (keyCode) {
case KeyCodes.escape:
if (this.state.suggestionsVisible) {
this.setState({ suggestionsVisible: false });
Expand All @@ -454,7 +457,9 @@ export class BasePicker<T, P extends IBasePickerProps<T>> extends BaseComponent<

case KeyCodes.tab:
case KeyCodes.enter:
if (!ev.shiftKey && this.suggestionStore.hasSelectedSuggestion() && this.state.suggestionsVisible) {
if (this.suggestionElement.hasSuggestedActionSelected()) {
this.suggestionElement.executeSelectedAction();
} else if (!ev.shiftKey && this.suggestionStore.hasSelectedSuggestion() && this.state.suggestionsVisible) {
this.completeSuggestion();
ev.preventDefault();
ev.stopPropagation();
Expand Down Expand Up @@ -488,34 +493,47 @@ export class BasePicker<T, P extends IBasePickerProps<T>> extends BaseComponent<

case KeyCodes.up:
if (ev.target === this.input.inputElement && this.state.suggestionsVisible) {
if (this.state.moreSuggestionsAvailable && this.suggestionElement.props.searchForMoreText && this.suggestionStore.currentIndex === 0) {
this.suggestionElement.focusSearchForMoreButton();
this.suggestionStore.deselectAllSuggestions();
this.forceUpdate();
if (this.suggestionElement.tryHandleKeyDown(keyCode, this.suggestionStore.currentIndex)) {
ev.preventDefault();
ev.stopPropagation();
} else {
if (this.suggestionStore.previousSuggestion()) {
if (this.suggestionElement.hasSuggestedAction() && this.suggestionStore.currentIndex === 0) {
ev.preventDefault();
ev.stopPropagation();
this.onSuggestionSelect();
this.suggestionElement.focusAboveSuggestions();
this.suggestionStore.deselectAllSuggestions();
this.forceUpdate();
} else {
if (this.suggestionStore.previousSuggestion()) {
ev.preventDefault();
ev.stopPropagation();
this.onSuggestionSelect();
}
}
}
}
break;

case KeyCodes.down:
if (ev.target === this.input.inputElement && this.state.suggestionsVisible) {
if (this.state.moreSuggestionsAvailable && this.suggestionElement.props.searchForMoreText && (this.suggestionStore.currentIndex + 1) === this.suggestionStore.suggestions.length) {
this.suggestionElement.focusSearchForMoreButton();
this.suggestionStore.deselectAllSuggestions();
this.forceUpdate();
if (this.suggestionElement.tryHandleKeyDown(keyCode, this.suggestionStore.currentIndex)) {
ev.preventDefault();
ev.stopPropagation();
} else {
if (this.suggestionStore.nextSuggestion()) {
if (this.suggestionElement.hasSuggestedAction() && (this.suggestionStore.currentIndex + 1) === this.suggestionStore.suggestions.length) {
ev.preventDefault();
ev.stopPropagation();
this.onSuggestionSelect();
this.suggestionElement.focusBelowSuggestions();
this.suggestionStore.deselectAllSuggestions();
this.forceUpdate();
} else {
if (this.suggestionStore.nextSuggestion()) {
ev.preventDefault();
ev.stopPropagation();
this.onSuggestionSelect();
}
}
}

}
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ export interface IBasePickerSuggestionsProps {
* The text that should appear on the button to search for more.
*/
searchForMoreText?: string;
/**
* The text that appears indicating to the use to force resolve the input
*/
forceResolveText?: string;
/**
* The text to display while the results are loading.
*/
Expand Down
Loading