From ec3516c61a73accf3af963d7a9a5395008645c10 Mon Sep 17 00:00:00 2001 From: Stanley Yao Date: Tue, 6 Feb 2018 14:28:57 -0800 Subject: [PATCH 01/23] Add multiSelect for ComboBox --- .../src/components/ComboBox/ComboBox.tsx | 397 +++++++++++------- .../src/components/ComboBox/ComboBox.types.ts | 16 + .../examples/ComboBox.Basic.Example.tsx | 17 + 3 files changed, 280 insertions(+), 150 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx index 22d0875891a1f0..a895a0ddb0759d 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx +++ b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx @@ -3,6 +3,7 @@ import { IComboBoxOption, IComboBoxProps } from './ComboBox.types'; import { DirectionalHint } from '../../common/DirectionalHint'; import { Callout } from '../../Callout'; import { Label } from '../../Label'; +import { Checkbox } from '../../Checkbox'; import { CommandButton, IconButton @@ -11,6 +12,7 @@ import { BaseAutoFill } from '../pickers/AutoFill/BaseAutoFill'; import { autobind, BaseComponent, + css, divProperties, findIndex, getId, @@ -38,8 +40,8 @@ export interface IComboBoxState { // The open state isOpen?: boolean; - // The currently selected index (-1 if no index is selected) - selectedIndex: number; + // The currently selected indices + selectedIndices?: number[]; // The focused state of the comboBox focused?: boolean; @@ -131,6 +133,8 @@ export class ComboBox extends BaseComponent { private _scrollIdleTimeoutId: number | undefined; + private static Option: string = 'option'; + // Determines if we should be setting // focus back to the input when the menu closes. // The general rule of thumb is if the menu was launched @@ -146,19 +150,26 @@ export class ComboBox extends BaseComponent { 'defaultSelectedKey': 'selectedKey', 'value': 'defaultSelectedKey', 'selectedKey': 'value', - 'dropdownWidth': 'useComboBoxAsMenuWidth' + 'dropdownWidth': 'useComboBoxAsMenuWidth', + 'multiSelect': 'defaultSelectedKey' }); this._id = props.id || getId('ComboBox'); - let selectedKey = props.defaultSelectedKey !== undefined ? props.defaultSelectedKey : props.selectedKey; + let selectedKeys = []; + if (props.multiSelect) { + selectedKeys = (props.defaultSelectedKeys ? props.defaultSelectedKeys : props.selectedKeys) || []; + } else { + selectedKeys.push(props.defaultSelectedKey ? props.defaultSelectedKey : props.selectedKey); + } + this._isScrollIdle = true; - let index: number = this._getSelectedIndex(props.options, selectedKey); + let initialSelectedIndices: number[] = this._getSelectedIndices(props.options, selectedKeys); this.state = { isOpen: false, - selectedIndex: index, + selectedIndices: initialSelectedIndices, focused: false, suggestedDisplayValue: '', currentOptions: this.props.options, @@ -179,11 +190,11 @@ export class ComboBox extends BaseComponent { if (newProps.selectedKey !== this.props.selectedKey || newProps.value !== this.props.value || newProps.options !== this.props.options) { - - let index: number = this._getSelectedIndex(newProps.options, newProps.selectedKey); + let selectedKeys: (string | number | undefined)[] = (this.props.multiSelect ? newProps.selectedKeys : [newProps.selectedKey]) || []; + let indices: number[] = this._getSelectedIndices(newProps.options, selectedKeys); this.setState({ - selectedIndex: index, + selectedIndices: indices, currentOptions: newProps.options }); } @@ -199,7 +210,7 @@ export class ComboBox extends BaseComponent { let { isOpen, focused, - selectedIndex, + selectedIndices, currentPendingValueValidIndex } = this.state; @@ -232,7 +243,7 @@ export class ComboBox extends BaseComponent { // we need to set selection if (this._focusInputAfterClose && (prevState.isOpen && !isOpen || (focused && - ((!isOpen && prevState.selectedIndex !== selectedIndex) || + ((!isOpen && !this.props.multiSelect && prevState.selectedIndices && selectedIndices && prevState.selectedIndices[0] !== selectedIndices[0]) || !allowFreeform || value !== prevProps.value) ))) { this._select(); @@ -274,7 +285,7 @@ export class ComboBox extends BaseComponent { styles: customStyles, theme, } = this.props; - let { isOpen, selectedIndex, focused, suggestedDisplayValue } = this.state; + let { isOpen, selectedIndices, focused, suggestedDisplayValue } = this.state; this._currentVisibleValue = this._getVisibleValue(); let divProps = getNativeProps(this.props, divProperties); @@ -293,58 +304,58 @@ export class ComboBox extends BaseComponent { ); return ( -
- { label && ( - - ) } +
+ {label && ( + + )}
= 0 ? (id + '-list' + selectedIndex) : null) } - aria-disabled={ disabled } - aria-owns={ (id + '-list') } - spellCheck={ false } - defaultVisibleValue={ this._currentVisibleValue } - suggestedDisplayValue={ suggestedDisplayValue } - updateValueInWillReceiveProps={ this._onUpdateValueInAutoFillWillReceiveProps } - shouldSelectFullInputValueInComponentDidUpdate={ this._onShouldSelectFullInputValueInAutoFillComponentDidUpdate } + aria-readonly={((allowFreeform || disabled) ? null : 'true')} + readOnly={disabled || !allowFreeform} + aria-labelledby={(label && (id + '-label'))} + aria-label={((ariaLabel && !label) && ariaLabel)} + aria-describedby={(id + '-option')} + // aria-activedescendant={ (isOpen && (selectedIndex as number) >= 0 ? (id + '-list' + selectedIndex) : null) } + aria-disabled={disabled} + aria-owns={(id + '-list')} + spellCheck={false} + defaultVisibleValue={this._currentVisibleValue} + suggestedDisplayValue={suggestedDisplayValue} + updateValueInWillReceiveProps={this._onUpdateValueInAutoFillWillReceiveProps} + shouldSelectFullInputValueInComponentDidUpdate={this._onShouldSelectFullInputValueInAutoFillComponentDidUpdate} />
- { isOpen && ( + {isOpen && ( (onRenderContainer as any)({ ...this.props, onRenderList, @@ -353,13 +364,13 @@ export class ComboBox extends BaseComponent { options: this.state.currentOptions.map((item, index) => ({ ...item, index: index })) }, this._onRenderContainer) - ) } + )} { errorMessage &&
- { errorMessage } + {errorMessage}
}
@@ -436,12 +447,13 @@ export class ComboBox extends BaseComponent { autoComplete } = this.props; let { - selectedIndex, + selectedIndices, currentPendingValueValidIndex, currentOptions, currentPendingValue, suggestedDisplayValue, - isOpen + isOpen, + focused } = this.state; let currentPendingIndexValid = this._indexWithinBounds(currentOptions, currentPendingValueValidIndex); @@ -452,41 +464,63 @@ export class ComboBox extends BaseComponent { return value; } - let index = selectedIndex; + // Values to display in the BaseAutoFill area + let displayValues = []; - if (allowFreeform) { - // If we are allowing freeform and autocomplete is also true - // and we've got a pending value that matches an option, remember - // the matched option's index - if (autoComplete === 'on' && currentPendingIndexValid) { - index = currentPendingValueValidIndex; + if (this.props.multiSelect) { + // MUlti-select + if (focused) { + let index: number = -1; + if (autoComplete === 'on' && currentPendingIndexValid) { + index = currentPendingValueValidIndex; + } + displayValues.push(currentPendingValue !== '' ? currentPendingValue : (this._indexWithinBounds(currentOptions, index) ? currentOptions[index].text : '')); + } else { + for (let idx = 0; selectedIndices && (idx < selectedIndices.length); idx ++) { + let index: number = selectedIndices[idx]; + displayValues.push(this._indexWithinBounds(currentOptions, index) ? currentOptions[index].text : suggestedDisplayValue); + } } - - // Since we are allowing freeform, if there is currently a nonempty pending value, use that - // otherwise use the index determined above (falling back to '' if we did not get a valid index) - return currentPendingValue !== '' ? currentPendingValue : (this._indexWithinBounds(currentOptions, index) ? currentOptions[index].text : ''); - } else { - - // If we are not allowing freeform and have a - // valid index that matches the pending value, - // we know we will need some version of the pending value - if (currentPendingIndexValid) { - - // If autoComplete is on, return the - // raw pending value, otherwise remember - // the matched option's index - if (autoComplete === 'on') { - return currentPendingValue; + // Single-select + let index: number = selectedIndices && selectedIndices[0] || -1; + if (allowFreeform) { + // If we are allowing freeform and autocomplete is also true + // and we've got a pending value that matches an option, remember + // the matched option's index + if (autoComplete === 'on' && currentPendingIndexValid) { + index = currentPendingValueValidIndex; } - index = currentPendingValueValidIndex; + // Since we are allowing freeform, if there is currently a nonempty pending value, use that + // otherwise use the index determined above (falling back to '' if we did not get a valid index) + displayValues.push(currentPendingValue !== '' ? currentPendingValue : (this._indexWithinBounds(currentOptions, index) ? currentOptions[index].text : '')); + } else { + // If we are not allowing freeform and have a + // valid index that matches the pending value, + // we know we will need some version of the pending value + if (currentPendingIndexValid && autoComplete === 'on') { + // If autoComplete is on, return the + // raw pending value, otherwise remember + // the matched option's index + index = currentPendingValueValidIndex; + displayValues.push(currentPendingValue); + } else { + displayValues.push(this._indexWithinBounds(currentOptions, index) ? currentOptions[index].text : suggestedDisplayValue); + } } + } - // If we have a valid index then return the text value of that option, - // otherwise return the suggestedDisplayValue - return this._indexWithinBounds(currentOptions, index) ? currentOptions[index].text : suggestedDisplayValue; + // If we have a valid index then return the text value of that option, + // otherwise return the suggestedDisplayValue + let displayString: string = ''; + for (let idx = 0; idx < displayValues.length; idx++) { + if (idx > 0) { + displayString += ', '; + } + displayString += displayValues[idx]; } + return displayString; } /** @@ -578,7 +612,7 @@ export class ComboBox extends BaseComponent { currentPendingValue, currentPendingValueValidIndex, currentOptions, - selectedIndex + selectedIndices } = this.state; if (this.props.autoComplete === 'on') { @@ -624,7 +658,7 @@ export class ComboBox extends BaseComponent { // If we get here, either autoComplete is on or we did not find a match with autoComplete on. // Remember we are not allowing freeform, so at this point, if we have a pending valid value index // use that; otherwise use the selectedIndex - let index = currentPendingValueValidIndex >= 0 ? currentPendingValueValidIndex : selectedIndex; + let index = currentPendingValueValidIndex >= 0 ? currentPendingValueValidIndex : (selectedIndices && selectedIndices[0] || -1); // todo: stanleyy // Since we are not allowing freeform, we need to // set both the pending and suggested values/index @@ -681,7 +715,10 @@ export class ComboBox extends BaseComponent { */ private _setSelectedIndex(index: number, searchDirection: SearchDirection = SearchDirection.none) { let { onChanged } = this.props; - let { selectedIndex, currentOptions } = this.state; + let { selectedIndices, currentOptions } = this.state; + if (!selectedIndices) { + selectedIndices = []; + } // Find the next selectable index, if searchDirection is none // we will get our starting index back @@ -693,12 +730,25 @@ export class ComboBox extends BaseComponent { // Are we at a new index? If so, update the state, otherwise // there is nothing to do - if (index !== selectedIndex) { + if (this.props.multiSelect || (selectedIndices && selectedIndices.length === 1 && selectedIndices[0] !== index)) { let option: IComboBoxOption = currentOptions[index]; + if (!option) { + return; + } + if (this.props.multiSelect) { + option.selected = !option.selected; + if (option.selected && selectedIndices.indexOf(index) < 0) { + selectedIndices.push(index); + } else if (!option.selected && selectedIndices.indexOf(index) >= 0) { + selectedIndices = selectedIndices.filter((value: number) => value != index); + } + } else { + selectedIndices[0] = index; + } // Set the selected option this.setState({ - selectedIndex: index + selectedIndices: selectedIndices }); // Did the creator give us an onChanged callback? @@ -712,6 +762,13 @@ export class ComboBox extends BaseComponent { } } + private _removeSelectedIndex(index: number) { + let selectedIndices = this.state.selectedIndices && this.state.selectedIndices.filter((idx: number) => idx !== index) || []; + this.setState({ + selectedIndices: selectedIndices + }); + } + /** * Focus (and select) the content of the input * and set the focused state @@ -765,7 +822,6 @@ export class ComboBox extends BaseComponent { */ @autobind private _onBlur(event: React.FocusEvent) { - // Do nothing if the blur is coming from something // inside the comboBox root or the comboBox menu since // it we are not really bluring from the whole comboBox @@ -793,6 +849,7 @@ export class ComboBox extends BaseComponent { autoComplete } = this.props; let { + selectedIndices, currentPendingValue, currentPendingValueValidIndex, currentOptions, @@ -829,10 +886,15 @@ export class ComboBox extends BaseComponent { // If we are not controlled, create a new option let newOption: IComboBoxOption = { key: currentPendingValue, text: currentPendingValue }; let newOptions: IComboBoxOption[] = [...currentOptions, newOption]; - + if (selectedIndices) { + if (!this.props.multiSelect) { + selectedIndices = []; + } + selectedIndices.push(newOptions.length - 1); + } this.setState({ currentOptions: newOptions, - selectedIndex: newOptions.length - 1 + selectedIndices: selectedIndices }); } } else if (currentPendingValueValidIndex >= 0) { @@ -861,26 +923,26 @@ export class ComboBox extends BaseComponent { return ( -
- { (onRenderList as any)({ ...props }, this._onRenderList) } +
+ {(onRenderList as any)({ ...props }, this._onRenderList)}
- { onRenderLowerContent(this.props, this._onRenderLowerContent) } + {onRenderLowerContent(this.props, this._onRenderLowerContent)} ); } @@ -896,12 +958,12 @@ export class ComboBox extends BaseComponent { let id = this._id; return (
- { options.map((item) => (onRenderItem as any)(item, this._onRenderItem)) } + {options.map((item) => (onRenderItem as any)(item, this._onRenderItem))}
); } @@ -933,8 +995,8 @@ export class ComboBox extends BaseComponent { return (
); } @@ -945,8 +1007,8 @@ export class ComboBox extends BaseComponent { let { onRenderOption = this._onRenderOption } = this.props; return ( -
- { onRenderOption(item, this._onRenderOption) } +
+ {onRenderOption(item, this._onRenderOption)}
); } @@ -959,26 +1021,46 @@ export class ComboBox extends BaseComponent { const rootClassNames = getComboBoxOptionClassNames(this._getCurrentOptionStyles(item)).root; return ( - { - { onRenderOption(item, this._onRenderOption) } - - } - + !this.props.multiSelect ? ( + + { + + {onRenderOption(item, this._onRenderOption)} + + } + + ) : ( + + {onRenderOption(item, this._onRenderOption)} + + ) ); } @@ -1005,7 +1087,15 @@ export class ComboBox extends BaseComponent { return false; } - return this._getPendingSelectedIndex(true /* includePendingValue */) === index; + if (this._getPendingSelectedIndex(true /* includePendingValue */) === index) { + return true; + } + + let idxOfSelectedIndex: number = -1; + if ((index !== undefined) && this.state.selectedIndices) { + idxOfSelectedIndex = this.state.selectedIndices.indexOf(index); + } + return (idxOfSelectedIndex >= 0); } /** @@ -1018,7 +1108,7 @@ export class ComboBox extends BaseComponent { currentPendingValueValidIndexOnHover, currentPendingValueValidIndex, currentPendingValue, - selectedIndex + selectedIndices } = this.state; return ( @@ -1026,7 +1116,7 @@ export class ComboBox extends BaseComponent { currentPendingValueValidIndexOnHover : (currentPendingValueValidIndex >= 0 || (includeCurrentPendingValue && currentPendingValue !== '')) ? currentPendingValueValidIndex : - selectedIndex + (selectedIndices && selectedIndices[0] || -1) // todo: stanleyy ); } @@ -1058,12 +1148,12 @@ export class ComboBox extends BaseComponent { let { currentPendingValueValidIndex, currentPendingValue, - selectedIndex + selectedIndices } = this.state; if (onScrollToItem) { // Use the custom scroll handler - onScrollToItem((currentPendingValueValidIndex >= 0 || currentPendingValue !== '') ? currentPendingValueValidIndex : selectedIndex); + onScrollToItem((currentPendingValueValidIndex >= 0 || currentPendingValue !== '') ? currentPendingValueValidIndex : (selectedIndices && selectedIndices[0] || -1)); // todo: stanleyy } else if (this._selectedElement && this._selectedElement.offsetParent) { // We are using refs, scroll the ref into view if (scrollSelectedToTop) { @@ -1096,7 +1186,7 @@ export class ComboBox extends BaseComponent { @autobind private _onRenderOption(item: IComboBoxOption): JSX.Element { const optionClassNames = getComboBoxOptionClassNames(this._getCurrentOptionStyles(item)); - return { item.text }; + return {item.text}; } /** @@ -1107,9 +1197,12 @@ export class ComboBox extends BaseComponent { private _onItemClick(index: number | undefined): () => void { return (): void => { this._setSelectedIndex(index as number); - this.setState({ - isOpen: false - }); + if (!this.props.multiSelect) { + // only close the callout when it's in single-select mode + this.setState({ + isOpen: false + }); + } }; } @@ -1134,15 +1227,19 @@ export class ComboBox extends BaseComponent { /** * Get the index of the option that is marked as selected * @param options - the comboBox options - * @param selectedKey - the known selected key to find + * @param selectedKeys - the known selected key to find * @returns { number } - the index of the selected option, -1 if not found */ - private _getSelectedIndex(options: IComboBoxOption[] | undefined, selectedKey: string | number | undefined): number { - if (options === undefined || selectedKey === undefined) { - return -1; + private _getSelectedIndices(options: IComboBoxOption[] | undefined, selectedKeys: (string | number | undefined)[]): number[] { + let selectedIndices: any[] = []; + if (options === undefined || selectedKeys === undefined) { + return selectedIndices; } - return findIndex(options, (option => (option.selected || option.key === selectedKey))); + for (let selectedKey of selectedKeys) { + selectedIndices.push(findIndex(options, (option => (option.selected || option.key === selectedKey)))); + } + return selectedIndices; } /** @@ -1153,12 +1250,13 @@ export class ComboBox extends BaseComponent { */ private _resetSelectedIndex() { let { - selectedIndex, + selectedIndices, currentOptions } = this.state; this._comboBox.clear(); this._clearPendingInfo(); + let selectedIndex: number = selectedIndices && selectedIndices[0] || -1; // todo: stanleyy if (selectedIndex > 0 && selectedIndex < currentOptions.length) { this.setState({ suggestedDisplayValue: currentOptions[selectedIndex].text @@ -1219,7 +1317,6 @@ export class ComboBox extends BaseComponent { private _setPendingInfoFromIndexAndDirection(index: number, searchDirection: SearchDirection) { let { isOpen, - selectedIndex, currentOptions } = this.state; diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.types.ts b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.types.ts index 2abc4a44c830cc..8a61b1ed9a82d2 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.types.ts +++ b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.types.ts @@ -132,6 +132,22 @@ export interface IComboBoxProps extends ISelectableDroppableTextProps * Whether to use the ComboBoxes width as the menu's width */ useComboBoxAsMenuWidth?: boolean; + + /** + * Optional mode indicates if multi-choice selections is allowed. Default to false + */ + multiSelect?: boolean; + + /** + * Keys that will be initially used to set selected items. + */ + defaultSelectedKeys?: string[] | number[]; + + /** + * Keys of the selected items. If you provide this, you must maintain selection + * state by observing onChange events and passing a new value in when changed. + */ + selectedKeys?: string[] | number[]; } export interface IComboBoxStyles { diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx b/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx index b60a6d25d7c0c9..edc326b6c765e3 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx @@ -89,6 +89,23 @@ export class ComboBoxBasicExample extends React.Component<{}, { onClick={ this._basicComboBoxOnClick } /> + console.log('onFocus called') } + onBlur={ () => console.log('onBlur called') } + onMenuOpen={ () => console.log('ComboBox menu opened') } + // tslint:enable:jsx-no-lambda + /> + Date: Tue, 6 Feb 2018 16:13:23 -0800 Subject: [PATCH 02/23] Unbreak a unit test --- .../src/components/ComboBox/ComboBox.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx index bfff925c3a0a3c..5b2dbc40d0a430 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx +++ b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx @@ -484,7 +484,7 @@ export class ComboBox extends BaseComponent { } } else { // Single-select - let index: number = selectedIndices && selectedIndices[0] || -1; + let index: number = this._getFirstSelectedIndex(); if (allowFreeform) { // If we are allowing freeform and autocomplete is also true // and we've got a pending value that matches an option, remember @@ -659,7 +659,7 @@ export class ComboBox extends BaseComponent { // If we get here, either autoComplete is on or we did not find a match with autoComplete on. // Remember we are not allowing freeform, so at this point, if we have a pending valid value index // use that; otherwise use the selectedIndex - let index = currentPendingValueValidIndex >= 0 ? currentPendingValueValidIndex : (selectedIndices && selectedIndices[0] || -1); // todo: stanleyy + let index = currentPendingValueValidIndex >= 0 ? currentPendingValueValidIndex : this._getFirstSelectedIndex(); // Since we are not allowing freeform, we need to // set both the pending and suggested values/index @@ -668,6 +668,10 @@ export class ComboBox extends BaseComponent { this._setPendingInfoFromIndex(index); } + private _getFirstSelectedIndex(): number { + return (this.state.selectedIndices && this.state.selectedIndices.length > 0) ? this.state.selectedIndices[0] : -1; + } + /** * Walk along the options starting at the index, stepping by the delta (positive or negative) * looking for the next valid selectable index (e.g. skipping headings and dividers) @@ -1116,8 +1120,7 @@ export class ComboBox extends BaseComponent { currentPendingValueValidIndexOnHover >= 0 ? currentPendingValueValidIndexOnHover : (currentPendingValueValidIndex >= 0 || (includeCurrentPendingValue && currentPendingValue !== '')) ? - currentPendingValueValidIndex : - (selectedIndices && selectedIndices[0] || -1) // todo: stanleyy + currentPendingValueValidIndex : this._getFirstSelectedIndex() ); } @@ -1154,7 +1157,7 @@ export class ComboBox extends BaseComponent { if (onScrollToItem) { // Use the custom scroll handler - onScrollToItem((currentPendingValueValidIndex >= 0 || currentPendingValue !== '') ? currentPendingValueValidIndex : (selectedIndices && selectedIndices[0] || -1)); // todo: stanleyy + onScrollToItem((currentPendingValueValidIndex >= 0 || currentPendingValue !== '') ? currentPendingValueValidIndex : this._getFirstSelectedIndex()); } else if (this._selectedElement && this._selectedElement.offsetParent) { // We are using refs, scroll the ref into view if (scrollSelectedToTop) { @@ -1257,7 +1260,7 @@ export class ComboBox extends BaseComponent { this._comboBox.clear(); this._clearPendingInfo(); - let selectedIndex: number = selectedIndices && selectedIndices[0] || -1; // todo: stanleyy + let selectedIndex: number = this._getFirstSelectedIndex(); if (selectedIndex > 0 && selectedIndex < currentOptions.length) { this.setState({ suggestedDisplayValue: currentOptions[selectedIndex].text From 7155aa8f45ab8934f174750b986c6b94c704fdef Mon Sep 17 00:00:00 2001 From: Stanley Yao Date: Tue, 6 Feb 2018 16:36:34 -0800 Subject: [PATCH 03/23] rush change --- .../stanleyy-fillin_2018-02-07-00-36.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 common/changes/office-ui-fabric-react/stanleyy-fillin_2018-02-07-00-36.json diff --git a/common/changes/office-ui-fabric-react/stanleyy-fillin_2018-02-07-00-36.json b/common/changes/office-ui-fabric-react/stanleyy-fillin_2018-02-07-00-36.json new file mode 100644 index 00000000000000..3930100a40a969 --- /dev/null +++ b/common/changes/office-ui-fabric-react/stanleyy-fillin_2018-02-07-00-36.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "office-ui-fabric-react", + "comment": "Add multiSelect capability for ComboBox", + "type": "minor" + } + ], + "packageName": "office-ui-fabric-react", + "email": "stanleyy@microsoft.com" +} \ No newline at end of file From f81f5955826239b6573578bbc4f63f629c450b88 Mon Sep 17 00:00:00 2001 From: Stanley Yao Date: Thu, 15 Mar 2018 11:09:58 -0700 Subject: [PATCH 04/23] bug fixes --- .../src/components/ComboBox/ComboBox.tsx | 65 ++++++++++++------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx index 60f6d7187c4d16..b3ce67f2038868 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx +++ b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx @@ -1100,7 +1100,7 @@ export class ComboBox extends BaseComponent { return false; } - if (this._getPendingSelectedIndex(true /* includePendingValue */) === index) { + if (!this.props.multiSelect && this._getPendingSelectedIndex(true /* includePendingValue */) === index) { return true; } @@ -1128,7 +1128,8 @@ export class ComboBox extends BaseComponent { currentPendingValueValidIndexOnHover >= 0 ? currentPendingValueValidIndexOnHover : (currentPendingValueValidIndex >= 0 || (includeCurrentPendingValue && currentPendingValue !== '')) ? - currentPendingValueValidIndex : this._getFirstSelectedIndex() + currentPendingValueValidIndex : + this.props.multiSelect ? 0 : this._getFirstSelectedIndex() ); } @@ -1249,7 +1250,10 @@ export class ComboBox extends BaseComponent { } for (let selectedKey of selectedKeys) { - selectedIndices.push(findIndex(options, (option => (option.selected || option.key === selectedKey)))); + let index = findIndex(options, (option => (option.selected || option.key === selectedKey))); + if (index > -1) { + selectedIndices.push(index); + } } return selectedIndices; } @@ -1362,7 +1366,8 @@ export class ComboBox extends BaseComponent { const { isOpen, currentOptions, - currentPendingValueValidIndexOnHover + currentPendingValueValidIndexOnHover, + selectedIndices } = this.state; if (disabled) { @@ -1374,28 +1379,38 @@ export class ComboBox extends BaseComponent { switch (ev.which) { case KeyCodes.enter: - // On enter submit the pending value - this._submitPendingValue(); - - // if we are open or - // if we are not allowing freeform or - // our we have no pending value - // and no valid pending index - // flip the open state - if ((isOpen || - ((!allowFreeform || - this.state.currentPendingValue === undefined || - this.state.currentPendingValue === null || - this.state.currentPendingValue.length <= 0) && - this.state.currentPendingValueValidIndex < 0))) { - this.setState({ - isOpen: !isOpen - }); - } - - // Allow TAB to propigate - if (ev.which as number === KeyCodes.tab) { + if (this.props.multiSelect && isOpen) { + // Toggle the current pending option + if (selectedIndices) { + let idxToRemove: number = selectedIndices.indexOf(index); + if (idxToRemove > -1) { + selectedIndices.splice(idxToRemove, 1); + } else { + selectedIndices.push(index); + } + this.setState({ + selectedIndices: selectedIndices + }); + } return; + } else { + // On enter submit the pending value + this._submitPendingValue(); + if ((isOpen || + ((!allowFreeform || + this.state.currentPendingValue === undefined || + this.state.currentPendingValue === null || + this.state.currentPendingValue.length <= 0) && + this.state.currentPendingValueValidIndex < 0))) { + // if we are open or + // if we are not allowing freeform or + // our we have no pending value + // and no valid pending index + // flip the open state + this.setState({ + isOpen: !isOpen + }); + } } break; From 7cd611ffc52e2cc25b2022d6daf6cb8d0bf226bd Mon Sep 17 00:00:00 2001 From: Stanley Yao Date: Thu, 15 Mar 2018 15:49:23 -0700 Subject: [PATCH 05/23] Merge from upstream and resolve local build issues --- .../src/components/ComboBox/ComboBox.tsx | 61 +++++++++---------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx index 52e424e809a25b..48c70b8ed9c6ea 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx +++ b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx @@ -12,14 +12,12 @@ import { Autofill } from '../Autofill/Autofill'; import { autobind, BaseComponent, - css, divProperties, findIndex, getId, getNativeProps, KeyCodes, - customizable, - css + customizable } from '../../Utilities'; import { SelectableOptionMenuItemType } from '../../utilities/selectableOption/SelectableOption.types'; import { @@ -151,7 +149,6 @@ export class ComboBox extends BaseComponent { this._id = props.id || getId('ComboBox'); - let selectedKeys = []; if (props.multiSelect) { selectedKeys = (props.defaultSelectedKeys ? props.defaultSelectedKeys : props.selectedKeys) || []; @@ -161,7 +158,7 @@ export class ComboBox extends BaseComponent { this._isScrollIdle = true; - let initialSelectedIndices: number[] = this._getSelectedIndices(props.options, selectedKeys); + const initialSelectedIndices: number[] = this._getSelectedIndices(props.options, selectedKeys); this.state = { isOpen: false, @@ -186,8 +183,8 @@ export class ComboBox extends BaseComponent { if (newProps.selectedKey !== this.props.selectedKey || newProps.value !== this.props.value || newProps.options !== this.props.options) { - let selectedKeys: (string | number | undefined)[] = (this.props.multiSelect ? newProps.selectedKeys : [newProps.selectedKey]) || []; - let indices: number[] = this._getSelectedIndices(newProps.options, selectedKeys); + const selectedKeys: (string | number | undefined)[] = (this.props.multiSelect ? newProps.selectedKeys : [newProps.selectedKey]) || []; + const indices: number[] = this._getSelectedIndices(newProps.options, selectedKeys); this.setState({ selectedIndices: indices, @@ -284,7 +281,7 @@ export class ComboBox extends BaseComponent { theme, title } = this.props; - let { isOpen, selectedIndices, focused, suggestedDisplayValue } = this.state; + const { isOpen, selectedIndices, focused, suggestedDisplayValue } = this.state; this._currentVisibleValue = this._getVisibleValue(); const divProps = getNativeProps(this.props, divProperties); @@ -457,7 +454,7 @@ export class ComboBox extends BaseComponent { allowFreeform, autoComplete } = this.props; - let { + const { selectedIndices, currentPendingValueValidIndex, currentOptions, @@ -476,19 +473,19 @@ export class ComboBox extends BaseComponent { } // Values to display in the BaseAutoFill area - let displayValues = []; + const displayValues = []; if (this.props.multiSelect) { // MUlti-select if (focused) { - let index: number = -1; + let index = -1; if (autoComplete === 'on' && currentPendingIndexValid) { index = currentPendingValueValidIndex; } displayValues.push(currentPendingValue !== '' ? currentPendingValue : (this._indexWithinBounds(currentOptions, index) ? currentOptions[index].text : '')); } else { for (let idx = 0; selectedIndices && (idx < selectedIndices.length); idx ++) { - let index: number = selectedIndices[idx]; + const index: number = selectedIndices[idx]; displayValues.push(this._indexWithinBounds(currentOptions, index) ? currentOptions[index].text : suggestedDisplayValue); } } @@ -524,7 +521,7 @@ export class ComboBox extends BaseComponent { // If we have a valid index then return the text value of that option, // otherwise return the suggestedDisplayValue - let displayString: string = ''; + let displayString = ''; for (let idx = 0; idx < displayValues.length; idx++) { if (idx > 0) { displayString += ', '; @@ -669,7 +666,7 @@ export class ComboBox extends BaseComponent { // If we get here, either autoComplete is on or we did not find a match with autoComplete on. // Remember we are not allowing freeform, so at this point, if we have a pending valid value index // use that; otherwise use the selectedIndex - let index = currentPendingValueValidIndex >= 0 ? currentPendingValueValidIndex : this._getFirstSelectedIndex(); + const index = currentPendingValueValidIndex >= 0 ? currentPendingValueValidIndex : this._getFirstSelectedIndex(); // Since we are not allowing freeform, we need to // set both the pending and suggested values/index @@ -729,8 +726,10 @@ export class ComboBox extends BaseComponent { * @param searchDirection - the direction to search along the options from the given index */ private _setSelectedIndex(index: number, searchDirection: SearchDirection = SearchDirection.none) { - let { onChanged, onPendingValueChanged } = this.props; - let { selectedIndices, currentOptions } = this.state; + const { onChanged, onPendingValueChanged } = this.props; + const { currentOptions } = this.state; + let { selectedIndices } = this.state; + if (!selectedIndices) { selectedIndices = []; } @@ -746,7 +745,7 @@ export class ComboBox extends BaseComponent { // Are we at a new index? If so, update the state, otherwise // there is nothing to do if (this.props.multiSelect || (selectedIndices && selectedIndices.length === 1 && selectedIndices[0] !== index)) { - let option: IComboBoxOption = currentOptions[index]; + const option: IComboBoxOption = currentOptions[index]; if (!option) { return; } @@ -784,7 +783,7 @@ export class ComboBox extends BaseComponent { } private _removeSelectedIndex(index: number) { - let selectedIndices = this.state.selectedIndices && this.state.selectedIndices.filter((idx: number) => idx !== index) || []; + const selectedIndices = this.state.selectedIndices && this.state.selectedIndices.filter((idx: number) => idx !== index) || []; this.setState({ selectedIndices: selectedIndices }); @@ -871,13 +870,13 @@ export class ComboBox extends BaseComponent { allowFreeform, autoComplete } = this.props; - let { - selectedIndices, + const { currentPendingValue, currentPendingValueValidIndex, currentOptions, currentPendingValueValidIndexOnHover } = this.state; + let { selectedIndices } = this.state; // If we allow freeform and we have a pending value, we // need to handle that @@ -907,8 +906,8 @@ export class ComboBox extends BaseComponent { onChanged(undefined, undefined, currentPendingValue); } else { // If we are not controlled, create a new option - let newOption: IComboBoxOption = { key: currentPendingValue, text: currentPendingValue }; - let newOptions: IComboBoxOption[] = [...currentOptions, newOption]; + const newOption: IComboBoxOption = { key: currentPendingValue, text: currentPendingValue }; + const newOptions: IComboBoxOption[] = [...currentOptions, newOption]; if (selectedIndices) { if (!this.props.multiSelect) { selectedIndices = []; @@ -1114,7 +1113,7 @@ export class ComboBox extends BaseComponent { return true; } - let idxOfSelectedIndex: number = -1; + let idxOfSelectedIndex = -1; if ((index !== undefined) && this.state.selectedIndices) { idxOfSelectedIndex = this.state.selectedIndices.indexOf(index); } @@ -1254,13 +1253,13 @@ export class ComboBox extends BaseComponent { * @returns { number } - the index of the selected option, -1 if not found */ private _getSelectedIndices(options: IComboBoxOption[] | undefined, selectedKeys: (string | number | undefined)[]): number[] { - let selectedIndices: any[] = []; + const selectedIndices: any[] = []; if (options === undefined || selectedKeys === undefined) { return selectedIndices; } - for (let selectedKey of selectedKeys) { - let index = findIndex(options, (option => (option.selected || option.key === selectedKey))); + for (const selectedKey of selectedKeys) { + const index = findIndex(options, (option => (option.selected || option.key === selectedKey))); if (index > -1) { selectedIndices.push(index); } @@ -1275,14 +1274,14 @@ export class ComboBox extends BaseComponent { * selected state text */ private _resetSelectedIndex() { - let { + const { selectedIndices, currentOptions } = this.state; this._comboBox.clear(); this._clearPendingInfo(); - let selectedIndex: number = this._getFirstSelectedIndex(); + const selectedIndex: number = this._getFirstSelectedIndex(); if (selectedIndex > 0 && selectedIndex < currentOptions.length) { this.setState({ suggestedDisplayValue: currentOptions[selectedIndex].text @@ -1341,7 +1340,7 @@ export class ComboBox extends BaseComponent { * @param searchDirection - the direction to search */ private _setPendingInfoFromIndexAndDirection(index: number, searchDirection: SearchDirection) { - let { + const { isOpen, currentOptions } = this.state; @@ -1427,7 +1426,7 @@ export class ComboBox extends BaseComponent { if (this.props.multiSelect && isOpen) { // Toggle the current pending option if (selectedIndices) { - let idxToRemove: number = selectedIndices.indexOf(index); + const idxToRemove: number = selectedIndices.indexOf(index); if (idxToRemove > -1) { selectedIndices.splice(idxToRemove, 1); } else { @@ -1455,7 +1454,7 @@ export class ComboBox extends BaseComponent { this.setState({ isOpen: !isOpen }); - } + } } break; From b15187cef25b1c45fd14125d819581d8d15aae26 Mon Sep 17 00:00:00 2001 From: Stanley Yao Date: Fri, 16 Mar 2018 08:19:30 -0700 Subject: [PATCH 06/23] Fix merge styles --- .../src/components/ComboBox/ComboBox.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx index 48c70b8ed9c6ea..da4b07aca45202 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx +++ b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx @@ -1040,7 +1040,7 @@ export class ComboBox extends BaseComponent { const { onRenderOption = this._onRenderOption } = this.props; const id = this._id; const isSelected: boolean = this._isOptionSelected(item.index); - const rootClassNames = getComboBoxOptionClassNames(this._getCurrentOptionStyles(item)).root; + const optionStyles = this._getCurrentOptionStyles(item); return ( !this.props.multiSelect ? ( @@ -1048,8 +1048,7 @@ export class ComboBox extends BaseComponent { id={id + '-list' + item.index} key={item.key} data-index={item.index} - className={rootClassNames} - styles={this._getCurrentOptionStyles(item)} + styles={optionStyles} checked={isSelected} onClick={this._onItemClick(item.index)} onMouseEnter={this._onOptionMouseEnter.bind(this, item.index)} @@ -1072,13 +1071,13 @@ export class ComboBox extends BaseComponent { ref={'option' + item.index} key={item.key} data-index={item.index} + styles={optionStyles} data-is-focusable={true} onChange={this._onItemClick(item.index!)} label={item.text} role='option' aria-selected={ isSelected ? 'true' : 'false' } checked={isSelected} - styles={this._getCurrentOptionStyles(item)} > {onRenderOption(item, this._onRenderOption)} From abc9efd906eee9ed8128ab837f807d1643386b8c Mon Sep 17 00:00:00 2001 From: Stanley Yao Date: Fri, 16 Mar 2018 08:59:03 -0700 Subject: [PATCH 07/23] Fix pending background --- .../src/components/ComboBox/ComboBox.styles.ts | 5 +++-- .../src/components/ComboBox/ComboBox.tsx | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.styles.ts b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.styles.ts index 1d357dc9ecd080..1361c542ad94fa 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.styles.ts +++ b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.styles.ts @@ -53,7 +53,8 @@ const getListOptionHighContrastStyles = memoizeFunction((theme: ITheme): IRawSty export const getOptionStyles = memoizeFunction(( theme: ITheme, customStylesForAllOptions?: Partial, - customOptionStylesForCurrentOption?: Partial + customOptionStylesForCurrentOption?: Partial, + isPending?: boolean ): Partial => { const { semanticColors, palette } = theme; @@ -67,7 +68,7 @@ export const getOptionStyles = memoizeFunction(( const optionStyles: IComboBoxOptionStyles = { root: [ { - backgroundColor: 'transparent', + backgroundColor: isPending ? ComboBoxOptionBackgroundHovered : 'transparent', boxSizing: 'border-box', cursor: 'pointer', display: 'block', diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx index da4b07aca45202..4380a771078114 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx +++ b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx @@ -1704,7 +1704,7 @@ export class ComboBox extends BaseComponent { const { comboBoxOptionStyles: customStylesForAllOptions } = this.props; const { styles: customStylesForCurrentOption } = item; - return getOptionStyles(this.props.theme!, customStylesForAllOptions, customStylesForCurrentOption); + return getOptionStyles(this.props.theme!, customStylesForAllOptions, customStylesForCurrentOption, this._isPendingOption(item)); } /** @@ -1728,4 +1728,8 @@ export class ComboBox extends BaseComponent { const autoComplete = !this.props.disabled && this.props.autoComplete === 'on'; return autoComplete ? (this.props.allowFreeform ? 'inline' : 'both') : 'none'; } + + private _isPendingOption(item: IComboBoxOption): boolean { + return item && item.index === this.state.currentPendingValueValidIndex; + } } From 78395cb442409fe3ee74851e102e913361a6d384 Mon Sep 17 00:00:00 2001 From: Stanley Yao Date: Fri, 16 Mar 2018 12:40:33 -0700 Subject: [PATCH 08/23] Unbreak unit test cases --- .../src/components/ComboBox/ComboBox.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx index 4380a771078114..96f6d4e7d1433a 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx +++ b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx @@ -744,7 +744,7 @@ export class ComboBox extends BaseComponent { // Are we at a new index? If so, update the state, otherwise // there is nothing to do - if (this.props.multiSelect || (selectedIndices && selectedIndices.length === 1 && selectedIndices[0] !== index)) { + if (this.props.multiSelect || selectedIndices.length < 1 || (selectedIndices.length === 1 && selectedIndices[0] !== index)) { const option: IComboBoxOption = currentOptions[index]; if (!option) { return; @@ -1050,6 +1050,7 @@ export class ComboBox extends BaseComponent { data-index={item.index} styles={optionStyles} checked={isSelected} + className={'ms-ComboBox-option'} onClick={this._onItemClick(item.index)} onMouseEnter={this._onOptionMouseEnter.bind(this, item.index)} onMouseMove={this._onOptionMouseMove.bind(this, item.index)} @@ -1072,6 +1073,7 @@ export class ComboBox extends BaseComponent { key={item.key} data-index={item.index} styles={optionStyles} + className={'ms-ComboBox-option'} data-is-focusable={true} onChange={this._onItemClick(item.index!)} label={item.text} From 558252d015da2fad6647002ba40fa2dad356e3e0 Mon Sep 17 00:00:00 2001 From: Stanley Yao Date: Mon, 19 Mar 2018 14:08:55 -0700 Subject: [PATCH 09/23] Fix the merge --- .../office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx index 6d1188c711b18e..4442408da62d8e 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx +++ b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx @@ -1066,7 +1066,7 @@ export class ComboBox extends BaseComponent { aria-selected={ isSelected ? 'true' : 'false' } checked={isSelected} > - {onRenderOption(item, this._onRenderOption)} + {onRenderOption(item, this._onRenderOptionContent)} ) ); From bc79fabae3ad58ac624ae9f176274b2322046e76 Mon Sep 17 00:00:00 2001 From: Stanley Yao Date: Tue, 20 Mar 2018 14:51:13 -0700 Subject: [PATCH 10/23] Add controled multi-select in the example page to make sure onChanged cb works --- .../examples/ComboBox.Basic.Example.tsx | 114 +++++++++++++++--- 1 file changed, 95 insertions(+), 19 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx b/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx index c153a91c42b5a5..62599d14a5eaa1 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx @@ -13,10 +13,34 @@ import { SelectableOptionMenuItemType } from 'office-ui-fabric-react/lib/utiliti import { IComboBox } from '../ComboBox.types'; import { PrimaryButton } from '../../../Button'; +const INITIAL_OPTIONS = +[ + { key: 'Header', text: 'Theme Fonts', itemType: SelectableOptionMenuItemType.Header }, + { key: 'A', text: 'Arial Black', fontFamily: '"Arial Black", "Arial Black_MSFontService", sans-serif' }, + { key: 'B', text: 'Time New Roman', fontFamily: '"Times New Roman", "Times New Roman_MSFontService", serif' }, + { key: 'C', text: 'Comic Sans MS', fontFamily: '"Comic Sans MS", "Comic Sans MS_MSFontService", fantasy' }, + { key: 'C1', text: 'Calibri', fontFamily: 'Calibri, Calibri_MSFontService, sans-serif' }, + { key: 'divider_2', text: '-', itemType: SelectableOptionMenuItemType.Divider }, + { key: 'Header1', text: 'Other Options', itemType: SelectableOptionMenuItemType.Header }, + { key: 'D', text: 'Option d' }, + { key: 'E', text: 'Option e' }, + { key: 'F', text: 'Option f' }, + { key: 'G', text: 'Option g' }, + { key: 'H', text: 'Option h' }, + { key: 'I', text: 'Option i' }, + { key: 'J', text: 'Option j' } +]; + export class ComboBoxBasicExample extends React.Component<{}, { + // For controled single select options: IComboBoxOption[]; selectedOptionKey?: string | number; value?: string; + + // For controled multi select + optionsMulti: IComboBoxOption[]; + selectedOptionKeys?: string[]; + valueMulti?: string; }> { private _testOptions = [{ key: 'Header', text: 'Theme Fonts', itemType: SelectableOptionMenuItemType.Header }, @@ -48,6 +72,7 @@ export class ComboBoxBasicExample extends React.Component<{}, { super(props); this.state = { options: [], + optionsMulti: [], selectedOptionKey: undefined, value: 'Calibri' }; @@ -62,6 +87,7 @@ export class ComboBoxBasicExample extends React.Component<{}, { public render() { const { options, selectedOptionKey, value } = this.state; + const { optionsMulti, selectedOptionKeys, valueMulti } = this.state; return (
@@ -243,6 +269,25 @@ export class ComboBoxBasicExample extends React.Component<{}, { // tslint:enable:jsx-no-lambda /> } + + console.log('onFocus called') } + onBlur={ () => console.log('onBlur called') } + onMenuOpen={ () => console.log('ComboBox menu opened') } + // tslint:enable:jsx-no-lambda + />
); @@ -282,30 +327,29 @@ export class ComboBoxBasicExample extends React.Component<{}, { return this.state.options; } - const newOptions = - [ - { key: 'Header', text: 'Theme Fonts', itemType: SelectableOptionMenuItemType.Header }, - { key: 'A', text: 'Arial Black', fontFamily: '"Arial Black", "Arial Black_MSFontService", sans-serif' }, - { key: 'B', text: 'Time New Roman', fontFamily: '"Times New Roman", "Times New Roman_MSFontService", serif' }, - { key: 'C', text: 'Comic Sans MS', fontFamily: '"Comic Sans MS", "Comic Sans MS_MSFontService", fantasy' }, - { key: 'C1', text: 'Calibri', fontFamily: 'Calibri, Calibri_MSFontService, sans-serif' }, - { key: 'divider_2', text: '-', itemType: SelectableOptionMenuItemType.Divider }, - { key: 'Header1', text: 'Other Options', itemType: SelectableOptionMenuItemType.Header }, - { key: 'D', text: 'Option d' }, - { key: 'E', text: 'Option e' }, - { key: 'F', text: 'Option f' }, - { key: 'G', text: 'Option g' }, - { key: 'H', text: 'Option h' }, - { key: 'I', text: 'Option i' }, - { key: 'J', text: 'Option j' } - ]; this.setState({ - options: newOptions, + options: INITIAL_OPTIONS, selectedOptionKey: 'C1', value: undefined }); - return newOptions; + return INITIAL_OPTIONS; + } + + @autobind + private _getOptionsMulti(currentOptions: IComboBoxOption[]): IComboBoxOption[] { + + if (this.state.options.length > 0) { + return this.state.optionsMulti; + } + + this.setState({ + optionsMulti: INITIAL_OPTIONS, + selectedOptionKey: 'C1', + value: undefined + }); + + return INITIAL_OPTIONS; } @autobind @@ -331,6 +375,38 @@ export class ComboBoxBasicExample extends React.Component<{}, { } } + @autobind + private _onChangedMulti(option: IComboBoxOption, index: number, value: string) { + if (option !== undefined) { + // User selected/de-selected an existing option + this.setState({ + selectedOptionKeys: this._updateSelectedOptionKeys(this.state.selectedOptionKeys || [], option), + value: undefined + }); + } else if (value !== undefined) { + // User typed a freeform option + const newOption: IComboBoxOption = { key: value, text: value }; + const updatedSelectedKeys: string[] = this.state.selectedOptionKeys ? [...this.state.selectedOptionKeys, newOption.key as string] : [newOption.key as string]; + this.setState({ + optionsMulti: [...this.state.optionsMulti, newOption], + selectedOptionKeys: updatedSelectedKeys, + value: undefined + }); + } + } + + private _updateSelectedOptionKeys(selectedKeys: string[], option: IComboBoxOption): string[] { + if (selectedKeys && option) { + const index = selectedKeys.indexOf(option.key as string); + if (option.selected && index < 0) { + selectedKeys.push(option.key as string); + } else { + selectedKeys.splice(index, 1); + } + } + return selectedKeys; + } + @autobind private _basicComboBoxOnClick(): void { this._basicCombobox.focus(true); From 09a52e782811c95d965c5713f4fe643a773f1f88 Mon Sep 17 00:00:00 2001 From: Stanley Yao Date: Tue, 20 Mar 2018 15:43:29 -0700 Subject: [PATCH 11/23] Remove trailing white spaces --- .../src/components/ComboBox/examples/ComboBox.Basic.Example.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx b/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx index 62599d14a5eaa1..638fb16c361c1d 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx @@ -392,7 +392,7 @@ export class ComboBoxBasicExample extends React.Component<{}, { selectedOptionKeys: updatedSelectedKeys, value: undefined }); - } + } } private _updateSelectedOptionKeys(selectedKeys: string[], option: IComboBoxOption): string[] { From 22c8e08e8b4622a261df915f43e27f9e03052e13 Mon Sep 17 00:00:00 2001 From: Stanley Yao Date: Tue, 20 Mar 2018 16:50:48 -0700 Subject: [PATCH 12/23] Fix bug: enter key will not trigger onChanged --- .../src/components/ComboBox/ComboBox.tsx | 33 ++++++------------- .../examples/ComboBox.Basic.Example.tsx | 6 ++-- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx index 421531b2995dce..2c313679e958cb 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx +++ b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx @@ -784,13 +784,6 @@ export class ComboBox extends BaseComponent { } } - private _removeSelectedIndex(index: number) { - const selectedIndices = this.state.selectedIndices && this.state.selectedIndices.filter((idx: number) => idx !== index) || []; - this.setState({ - selectedIndices: selectedIndices - }); - } - /** * Focus (and select) the content of the input * and set the focused state @@ -857,7 +850,9 @@ export class ComboBox extends BaseComponent { if (this.state.focused) { this.setState({ focused: false }); - this._submitPendingValue(); + if (!this.props.multiSelect) { + this._submitPendingValue(); + } } } @@ -1413,23 +1408,13 @@ export class ComboBox extends BaseComponent { switch (ev.which) { case KeyCodes.enter: + this._submitPendingValue(); if (this.props.multiSelect && isOpen) { - // Toggle the current pending option - if (selectedIndices) { - const idxToRemove: number = selectedIndices.indexOf(index); - if (idxToRemove > -1) { - selectedIndices.splice(idxToRemove, 1); - } else { - selectedIndices.push(index); - } - this.setState({ - selectedIndices: selectedIndices - }); - } - return; + this.setState({ + currentPendingValueValidIndex: index + }); } else { // On enter submit the pending value - this._submitPendingValue(); if ((isOpen || ((!allowFreeform || this.state.currentPendingValue === undefined || @@ -1450,7 +1435,9 @@ export class ComboBox extends BaseComponent { case KeyCodes.tab: // On enter submit the pending value - this._submitPendingValue(); + if (!this.props.multiSelect) { + this._submitPendingValue(); + } // If we are not allowing freeform // or the comboBox is open, flip the open state diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx b/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx index 638fb16c361c1d..2397d8f23eb3c9 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx @@ -345,7 +345,7 @@ export class ComboBoxBasicExample extends React.Component<{}, { this.setState({ optionsMulti: INITIAL_OPTIONS, - selectedOptionKey: 'C1', + selectedOptionKeys: [ 'C1' ], value: undefined }); @@ -381,7 +381,7 @@ export class ComboBoxBasicExample extends React.Component<{}, { // User selected/de-selected an existing option this.setState({ selectedOptionKeys: this._updateSelectedOptionKeys(this.state.selectedOptionKeys || [], option), - value: undefined + valueMulti: undefined }); } else if (value !== undefined) { // User typed a freeform option @@ -390,7 +390,7 @@ export class ComboBoxBasicExample extends React.Component<{}, { this.setState({ optionsMulti: [...this.state.optionsMulti, newOption], selectedOptionKeys: updatedSelectedKeys, - value: undefined + valueMulti: undefined }); } } From 94753a9c1e94eb5f28292800a69f820801fd1c42 Mon Sep 17 00:00:00 2001 From: Stanley Yao Date: Wed, 21 Mar 2018 12:27:44 -0700 Subject: [PATCH 13/23] Dummy change to trigger another build --- .../components/ComboBox/examples/ComboBox.Basic.Example.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx b/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx index 2397d8f23eb3c9..a8aaee17450e91 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx @@ -273,9 +273,9 @@ export class ComboBoxBasicExample extends React.Component<{}, { Date: Thu, 22 Mar 2018 14:52:41 -0700 Subject: [PATCH 14/23] refactor --- .../src/components/ComboBox/ComboBox.tsx | 43 +++++++++++++------ .../src/components/ComboBox/ComboBox.types.ts | 11 ----- .../examples/ComboBox.Basic.Example.tsx | 5 +-- .../src/components/Dropdown/Dropdown.tsx | 5 ++- .../SelectableDroppableText.types.ts | 4 +- 5 files changed, 38 insertions(+), 30 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx index 52ef4cd16a0809..586a66531aeaef 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx +++ b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx @@ -142,25 +142,14 @@ export class ComboBox extends BaseComponent { this._warnMutuallyExclusive({ 'defaultSelectedKey': 'selectedKey', - 'defaultSelectedKeys': 'selectedKeys', 'value': 'defaultSelectedKey', 'selectedKey': 'value', 'dropdownWidth': 'useComboBoxAsMenuWidth', }); - this._warnMutuallyExclusive({ - 'defaultSelectedKey': 'defaultSelectedKeys', - 'selectedKey': 'selectedKeys' - }); - this._id = props.id || getId('ComboBox'); - let selectedKeys = []; - if (props.multiSelect) { - selectedKeys = (props.defaultSelectedKeys ? props.defaultSelectedKeys : props.selectedKeys) || []; - } else { - selectedKeys.push(props.defaultSelectedKey ? props.defaultSelectedKey : props.selectedKey); - } + let selectedKeys: (string | number)[] = this._getSelectedKeys(props.defaultSelectedKey, props.selectedKey); this._isScrollIdle = true; @@ -189,7 +178,7 @@ export class ComboBox extends BaseComponent { if (newProps.selectedKey !== this.props.selectedKey || newProps.value !== this.props.value || newProps.options !== this.props.options) { - const selectedKeys: (string | number | undefined)[] = (this.props.multiSelect ? newProps.selectedKeys : [newProps.selectedKey]) || []; + const selectedKeys: string[] | number[] = this._getSelectedKeys(undefined, newProps.selectedKey); const indices: number[] = this._getSelectedIndices(newProps.options, selectedKeys); this.setState({ @@ -267,6 +256,34 @@ export class ComboBox extends BaseComponent { this._events.off(this._comboBoxWrapper.value); } + private _getSelectedKeys( + defaultSelectedKey: string | number | string[] | number[] | undefined, + selectedKey: string | number | string[] | number[] | undefined + ): string[] | number[] { + + let retKeys: string[] | number[] = []; + + if (defaultSelectedKey) { + if (defaultSelectedKey instanceof Array) { + retKeys = defaultSelectedKey; + } else if (typeof defaultSelectedKey === 'string') { + retKeys = [defaultSelectedKey as string]; + } else if (typeof defaultSelectedKey === 'number') { + retKeys = [defaultSelectedKey as number]; + } + } else if (selectedKey) { + if (selectedKey instanceof Array) { + retKeys = selectedKey; + } else if (typeof selectedKey === 'string') { + retKeys = [selectedKey as string]; + } else if (typeof selectedKey === 'number') { + retKeys = [selectedKey as number]; + } + } + + return retKeys; + } + // Primary Render public render() { const id = this._id; diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.types.ts b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.types.ts index 67cf50df6ac1bd..f42806a614f706 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.types.ts +++ b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.types.ts @@ -159,17 +159,6 @@ export interface IComboBoxProps extends ISelectableDroppableTextProps */ multiSelect?: boolean; - /** - * Keys that will be initially used to set selected items. - */ - defaultSelectedKeys?: string[] | number[]; - - /** - * Keys of the selected items. If you provide this, you must maintain selection - * state by observing onChange events and passing a new value in when changed. - */ - selectedKeys?: string[] | number[]; - /** * Sets the 'aria-hidden' attribute on the ComboBox's button element instructing screen readers how to handle the element. This element is hidden by default because all functionality is handled by the input element and the arrow button is only meant to be decorative. * @default true diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx b/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx index 9cb6f7663964ab..ffe90d3376b969 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx @@ -116,7 +116,7 @@ export class ComboBoxBasicExample extends React.Component<{}, { 0) { diff --git a/packages/office-ui-fabric-react/src/components/Dropdown/Dropdown.tsx b/packages/office-ui-fabric-react/src/components/Dropdown/Dropdown.tsx index 44733cd04ad06f..e099ca490076d3 100644 --- a/packages/office-ui-fabric-react/src/components/Dropdown/Dropdown.tsx +++ b/packages/office-ui-fabric-react/src/components/Dropdown/Dropdown.tsx @@ -628,7 +628,10 @@ export class Dropdown extends BaseComponent extends React.HTMLAttributes Date: Thu, 22 Mar 2018 15:29:26 -0700 Subject: [PATCH 15/23] Fix some minor bugs --- .../src/components/ComboBox/ComboBox.tsx | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx index 586a66531aeaef..61e21df8e95b95 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx +++ b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx @@ -149,7 +149,7 @@ export class ComboBox extends BaseComponent { this._id = props.id || getId('ComboBox'); - let selectedKeys: (string | number)[] = this._getSelectedKeys(props.defaultSelectedKey, props.selectedKey); + const selectedKeys: (string | number)[] = this._getSelectedKeys(props.defaultSelectedKey, props.selectedKey); this._isScrollIdle = true; @@ -256,34 +256,6 @@ export class ComboBox extends BaseComponent { this._events.off(this._comboBoxWrapper.value); } - private _getSelectedKeys( - defaultSelectedKey: string | number | string[] | number[] | undefined, - selectedKey: string | number | string[] | number[] | undefined - ): string[] | number[] { - - let retKeys: string[] | number[] = []; - - if (defaultSelectedKey) { - if (defaultSelectedKey instanceof Array) { - retKeys = defaultSelectedKey; - } else if (typeof defaultSelectedKey === 'string') { - retKeys = [defaultSelectedKey as string]; - } else if (typeof defaultSelectedKey === 'number') { - retKeys = [defaultSelectedKey as number]; - } - } else if (selectedKey) { - if (selectedKey instanceof Array) { - retKeys = selectedKey; - } else if (typeof selectedKey === 'string') { - retKeys = [selectedKey as string]; - } else if (typeof selectedKey === 'number') { - retKeys = [selectedKey as number]; - } - } - - return retKeys; - } - // Primary Render public render() { const id = this._id; @@ -1729,4 +1701,32 @@ export class ComboBox extends BaseComponent { private _isPendingOption(item: IComboBoxOption): boolean { return item && item.index === this.state.currentPendingValueValidIndex; } + + private _getSelectedKeys( + defaultSelectedKey: string | number | string[] | number[] | undefined, + selectedKey: string | number | string[] | number[] | undefined + ): string[] | number[] { + + let retKeys: string[] | number[] = []; + + if (defaultSelectedKey) { + if (defaultSelectedKey instanceof Array) { + retKeys = defaultSelectedKey; + } else if (typeof defaultSelectedKey === 'string') { + retKeys = [defaultSelectedKey as string]; + } else if (typeof defaultSelectedKey === 'number') { + retKeys = [defaultSelectedKey as number]; + } + } else if (selectedKey) { + if (selectedKey instanceof Array) { + retKeys = selectedKey; + } else if (typeof selectedKey === 'string') { + retKeys = [selectedKey as string]; + } else if (typeof selectedKey === 'number') { + retKeys = [selectedKey as number]; + } + } + + return retKeys; + } } From 76cffe7bd7a8495aded8e1dc5961f4c024fe8d1d Mon Sep 17 00:00:00 2001 From: Stanley Yao Date: Fri, 23 Mar 2018 12:19:18 -0700 Subject: [PATCH 16/23] Update some comments for ComboBox --- .../src/components/ComboBox/ComboBox.tsx | 7 +++++++ .../selectableOption/SelectableDroppableText.types.ts | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx index 61e21df8e95b95..344de995486a06 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx +++ b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx @@ -1702,6 +1702,13 @@ export class ComboBox extends BaseComponent { return item && item.index === this.state.currentPendingValueValidIndex; } + /** + * Given default selected key(s) and selected key(s), return the selected keys(s). + * When default selected key(s) are available, they take precedence and return them instead of selected key(s). + * + * @returns No matter what specific types the input parameters are, always return an array of + * either strings or numbers instead of premitive type. This normlization makes caller's logic easier. + */ private _getSelectedKeys( defaultSelectedKey: string | number | string[] | number[] | undefined, selectedKey: string | number | string[] | number[] | undefined diff --git a/packages/office-ui-fabric-react/src/utilities/selectableOption/SelectableDroppableText.types.ts b/packages/office-ui-fabric-react/src/utilities/selectableOption/SelectableDroppableText.types.ts index 7fc413898ed320..50b232e07bf3bc 100644 --- a/packages/office-ui-fabric-react/src/utilities/selectableOption/SelectableDroppableText.types.ts +++ b/packages/office-ui-fabric-react/src/utilities/selectableOption/SelectableDroppableText.types.ts @@ -31,12 +31,12 @@ export interface ISelectableDroppableTextProps extends React.HTMLAttributes Date: Fri, 23 Mar 2018 13:39:59 -0700 Subject: [PATCH 17/23] Minor bug fixes to the example page --- .../ComboBox/examples/ComboBox.Basic.Example.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx b/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx index ffe90d3376b969..ad451151d4f40f 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx @@ -73,7 +73,8 @@ export class ComboBoxBasicExample extends React.Component<{}, { options: [], optionsMulti: [], selectedOptionKey: undefined, - value: 'Calibri' + value: 'Calibri', + valueMulti: 'Calibri' }; for (let i = 0; i < 1000; i++) { @@ -278,6 +279,7 @@ export class ComboBoxBasicExample extends React.Component<{}, { allowFreeform={ true } autoComplete='on' options={ optionsMulti } + value={ valueMulti } onChanged={ this._onChangedMulti } onResolveOptions={ this._getOptionsMulti } onRenderOption={ this._onRenderFontOption } @@ -332,7 +334,7 @@ export class ComboBoxBasicExample extends React.Component<{}, { return INITIAL_OPTIONS; } - private _getOptionsMulti(currentOptions: IComboBoxOption[]): IComboBoxOption[] { + private _getOptionsMulti = (currentOptions: IComboBoxOption[]): IComboBoxOption[] => { if (this.state.options.length > 0) { return this.state.optionsMulti; @@ -341,7 +343,7 @@ export class ComboBoxBasicExample extends React.Component<{}, { this.setState({ optionsMulti: INITIAL_OPTIONS, selectedOptionKeys: [ 'C1' ], - value: undefined + valueMulti: undefined }); return INITIAL_OPTIONS; From 6bf66577933b1ad0b6f68d7cf82bc11148eb12e8 Mon Sep 17 00:00:00 2001 From: Stanley Yao Date: Fri, 23 Mar 2018 13:46:01 -0700 Subject: [PATCH 18/23] rush change --- .../stanleyy-fillin_2018-03-23-20-45.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 common/changes/office-ui-fabric-react/stanleyy-fillin_2018-03-23-20-45.json diff --git a/common/changes/office-ui-fabric-react/stanleyy-fillin_2018-03-23-20-45.json b/common/changes/office-ui-fabric-react/stanleyy-fillin_2018-03-23-20-45.json new file mode 100644 index 00000000000000..0b24d5ac7f85b8 --- /dev/null +++ b/common/changes/office-ui-fabric-react/stanleyy-fillin_2018-03-23-20-45.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "office-ui-fabric-react", + "comment": "ComboBox: Add some code comments. Minor bug fixes to the example page.", + "type": "patch" + } + ], + "packageName": "office-ui-fabric-react", + "email": "stanleyy@microsoft.com" +} \ No newline at end of file From d72d83878d666e5e916f0da59c0d05ee709ad864 Mon Sep 17 00:00:00 2001 From: Stanley Yao Date: Fri, 23 Mar 2018 14:00:42 -0700 Subject: [PATCH 19/23] Delete the old rush change file --- .../stanleyy-fillin_2018-02-07-00-36.json | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 common/changes/office-ui-fabric-react/stanleyy-fillin_2018-02-07-00-36.json diff --git a/common/changes/office-ui-fabric-react/stanleyy-fillin_2018-02-07-00-36.json b/common/changes/office-ui-fabric-react/stanleyy-fillin_2018-02-07-00-36.json deleted file mode 100644 index 3930100a40a969..00000000000000 --- a/common/changes/office-ui-fabric-react/stanleyy-fillin_2018-02-07-00-36.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "changes": [ - { - "packageName": "office-ui-fabric-react", - "comment": "Add multiSelect capability for ComboBox", - "type": "minor" - } - ], - "packageName": "office-ui-fabric-react", - "email": "stanleyy@microsoft.com" -} \ No newline at end of file From 9d8c122ed2b7270cd13e0ee3504d1dea159cfec8 Mon Sep 17 00:00:00 2001 From: Stanley Yao Date: Fri, 23 Mar 2018 14:21:13 -0700 Subject: [PATCH 20/23] Remove a trailing space --- .../office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx index 344de995486a06..e396c56c9199d7 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx +++ b/packages/office-ui-fabric-react/src/components/ComboBox/ComboBox.tsx @@ -1705,7 +1705,7 @@ export class ComboBox extends BaseComponent { /** * Given default selected key(s) and selected key(s), return the selected keys(s). * When default selected key(s) are available, they take precedence and return them instead of selected key(s). - * + * * @returns No matter what specific types the input parameters are, always return an array of * either strings or numbers instead of premitive type. This normlization makes caller's logic easier. */ From 421882b6e034693acbca8d1732abd132e7027556 Mon Sep 17 00:00:00 2001 From: Stanley Yao Date: Mon, 26 Mar 2018 15:08:39 -0700 Subject: [PATCH 21/23] Remove a redundant property from the ComboBox example --- .../components/ComboBox/examples/ComboBox.Basic.Example.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx b/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx index ad451151d4f40f..f66f68146c860e 100644 --- a/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx +++ b/packages/office-ui-fabric-react/src/components/ComboBox/examples/ComboBox.Basic.Example.tsx @@ -279,7 +279,6 @@ export class ComboBoxBasicExample extends React.Component<{}, { allowFreeform={ true } autoComplete='on' options={ optionsMulti } - value={ valueMulti } onChanged={ this._onChangedMulti } onResolveOptions={ this._getOptionsMulti } onRenderOption={ this._onRenderFontOption } @@ -336,7 +335,7 @@ export class ComboBoxBasicExample extends React.Component<{}, { private _getOptionsMulti = (currentOptions: IComboBoxOption[]): IComboBoxOption[] => { - if (this.state.options.length > 0) { + if (this.state.optionsMulti.length > 0) { return this.state.optionsMulti; } @@ -350,6 +349,7 @@ export class ComboBoxBasicExample extends React.Component<{}, { } private _onChanged = (option: IComboBoxOption, index: number, value: string): void => { + console.log('_onChanged() is called: option = ' + JSON.stringify(option)); if (option !== undefined) { this.setState({ selectedOptionKey: option.key, @@ -372,6 +372,7 @@ export class ComboBoxBasicExample extends React.Component<{}, { } private _onChangedMulti = (option: IComboBoxOption, index: number, value: string) => { + console.log('_onChangedMulti() is called: option = ' + JSON.stringify(option)); if (option !== undefined) { // User selected/de-selected an existing option this.setState({ From 824ebf638c664ac615821ed54405bc9ffc4399e5 Mon Sep 17 00:00:00 2001 From: Stanley Yao Date: Mon, 26 Mar 2018 15:10:08 -0700 Subject: [PATCH 22/23] rush chagne --- .../stanleyy-fillin_2018-03-26-22-09.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 common/changes/office-ui-fabric-react/stanleyy-fillin_2018-03-26-22-09.json diff --git a/common/changes/office-ui-fabric-react/stanleyy-fillin_2018-03-26-22-09.json b/common/changes/office-ui-fabric-react/stanleyy-fillin_2018-03-26-22-09.json new file mode 100644 index 00000000000000..76b8c6cb63864f --- /dev/null +++ b/common/changes/office-ui-fabric-react/stanleyy-fillin_2018-03-26-22-09.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "office-ui-fabric-react", + "comment": "Remove a redundant property from the ComboBox example", + "type": "patch" + } + ], + "packageName": "office-ui-fabric-react", + "email": "stanleyy@microsoft.com" +} \ No newline at end of file From 6a78413f08e3a0789bfecf7085657aa4187fa064 Mon Sep 17 00:00:00 2001 From: Stanley Yao Date: Mon, 26 Mar 2018 15:11:19 -0700 Subject: [PATCH 23/23] Remove old rush change file --- .../stanleyy-fillin_2018-03-23-20-45.json | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 common/changes/office-ui-fabric-react/stanleyy-fillin_2018-03-23-20-45.json diff --git a/common/changes/office-ui-fabric-react/stanleyy-fillin_2018-03-23-20-45.json b/common/changes/office-ui-fabric-react/stanleyy-fillin_2018-03-23-20-45.json deleted file mode 100644 index 0b24d5ac7f85b8..00000000000000 --- a/common/changes/office-ui-fabric-react/stanleyy-fillin_2018-03-23-20-45.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "changes": [ - { - "packageName": "office-ui-fabric-react", - "comment": "ComboBox: Add some code comments. Minor bug fixes to the example page.", - "type": "patch" - } - ], - "packageName": "office-ui-fabric-react", - "email": "stanleyy@microsoft.com" -} \ No newline at end of file