azure-devops-ui
Version:
React components for building web UI in Azure DevOps
1 lines • 12.1 kB
JavaScript
import"../../CommonImports";import"../../Core/core.css";import"./EditableDropdown.css";import*as React from"react";import{ObservableArray,ObservableLike,ObservableValue}from"../../Core/Observable";import{TimerManagement}from"../../Core/TimerManagement";import{equals,startsWith}from"../../Core/Util/String";import{Dropdown,DropdownCallout,DropdownExpandableTextField,filterItems}from"../../Dropdown";import{isListBoxItemVisible,ListBoxItemType,renderListBoxCell}from"../../ListBox";import{Observer}from"../../Observer";import*as Resources from"../../Resources.Dropdown";import{convertSpecialSymbols,css,KeyCode}from"../../Util";import{DropdownSelection}from"../../Utilities/DropdownSelection";import{EditableDropdownItemProvider}from"../../Utilities/EditableDropdownItemProvider";import{filterTreeItems,renderHighlightedText}from"../Dropdown/Dropdown";class CustomEditableDropdown extends React.Component{constructor(e){super(e),this.dropdown=React.createRef(),this.listBox=React.createRef(),this.filteredIndexMap=new ObservableValue([]),this.filterMatches=[],this.collapse=()=>{this.dropdown.current&&this.dropdown.current.collapse()},this.expand=()=>{this.dropdown.current&&this.dropdown.current.expand()},this.renderItem=(e,t,s,i)=>this.wrapWithFocusedIndexObserver(e,t,s,i,(e,t,s,i)=>{const r=this.filterMatches[e];return!i.render&&r&&r.length&&(i.render=(e,t,s,i)=>renderHighlightedText(e,t,s,i,r)),this.props.renderItem(e,t,s,i)}),this.wrapWithFocusedIndexObserver=(t,s,i,r,l)=>React.createElement(Observer,{focusedIndex:{observableValue:this.focusedIndex,filter:()=>{var e=this.filteredIndexMap.value[t];return e===this.focusedIndex.value||e===this.previousFocusedIndex}},key:`focused-observer-${t}-`+s},()=>{var e=this.filteredIndexMap.value[t]===this.focusedIndex.value&&(null==(e=r)?void 0:e.type)!==ListBoxItemType.Loading?Object.assign(Object.assign({},r),{className:css(r.className,"bolt-editable-dropdown-focused-item")}):Object.assign({},r);return l(t,s,i,e)}),this.onCollapse=()=>{const{allowFreeform:e,autoAccept:t,onCollapse:s,onValueChange:i,showTree:r,text:l}=this.props;s&&s(),this.selectedItemInList||-1<(n=this.itemProvider.value.findIndex((e,t)=>this.selection.selectable(t)&&e.text===ObservableLike.getValue(l||"")))&&this.selectIndex(n);var o,n=this.itemProvider.length-1;!e||this.selection.value.length&&this.selection.value[0].beginIndex!==n&&this.selectedItemInList||!this.itemProvider.hasExtraItem?r&&this.lastSelectedItem?i&&i(this.lastSelectedItem):this.selection.value.length&&(o=this.itemProvider.value[this.selection.value[0].beginIndex],i)&&i(o):((t||this.selectedItemInList||this.selectedFreeform)&&(o=this.itemProvider.value[n].id,i)&&i({id:o,text:o}),this.selectedFreeform=!1,this.selection.clear()),null!=(o=(n=this.props).onTextChange)&&o.call(n,null,""),this.isExpanded=!1,this.selectedItemInList=!1,this.lastSelectedItem=void 0,r&&(this.focusedIndex.value=-1),this.isFiltering=!1},this.onItemsChange=(e,t)=>{this.isExpanded&&("change"!==t&&this.filterItems(),this.selectSelectedTextItem())},this.selectSelectedTextItem=()=>{if(this.props.selectedText){const t=ObservableLike.getValue(this.props.selectedText);var e;t&&-1<(e=this.itemProvider.value.findIndex(e=>e.text===t))&&this.selection.select(e)}},this.onSelect=(e,t)=>{this.selectedItemInList=!0,this.lastSelectedItem=t},this.renderExpandable=o=>React.createElement(Observer,{focusedIndex:this.focusedIndex,selectedText:this.props.selectedText,text:this.props.text},e=>{var{allowTextSelection:t,inputId:s}=this.props,{selectedText:e,text:i}=e,r=this.getFocusedIndex();let l;-1<r&&this.itemProvider.value[r]&&(l=this.itemProvider.value[r].id);r=t&&e&&!this.isExpanded?e:i,t=Object.assign(Object.assign({},o),{ariaActiveDescendant:convertSpecialSymbols(l),editable:!0,showPrefix:!i,blurDismiss:!0,inputId:s,onChange:this.onTextChange,onKeyDown:this.onKeyDown,value:r});return null==(i=(e=this.props).renderExpandable)?void 0:i.call(e,t)}),this.renderCallout=e=>{e=Object.assign(Object.assign({},e),{focusOnMount:!1,excludeTabStop:!0,excludeFocusZone:!0,ignoreMouseDown:!0,listBoxRef:this.listBox});return this.props.renderCallout(e)},this.onExpand=()=>{var e,t;this.props.onExpand&&this.props.onExpand(),this.props.filterItems?(t=this.props.filterItems("",this.itemProvider.value),e=this.updateFilteredIndexMap(t.filteredIndexMap),this.filteredItems.value=t.filteredItems,this.focusItem(e)):(this.filteredItems.value=this.itemProvider.value,t=this.updateFilteredIndexMap(this.filteredItems.value.map((e,t)=>t)),this.focusItem(t)),this.isExpanded=!0},this.onTextChange=(e,t)=>{var s,i;return null!=(i=(s=this.props).onTextChange)&&i.call(s,e,t),this.props.allowFreeform?(this.itemProvider.hasExtraItem&&this.filteredItems.pop(),this.itemProvider.setTextValue(t),this.props.allowClear&&""===t&&(this.selection.clear(),null!=(s=(i=this.props).onValueChange))&&s.call(i)):""===t&&this.props.allowClear?(this.selection.clear(),null!=(s=(e=this.props).onValueChange)&&s.call(e)):-1<(i=this.itemProvider.value.findIndex(e=>e.text===t))&&this.selection.selectable(i)&&(this.selection.select(i),null!=(e=(s=this.props).onValueChange))&&e.call(s,this.itemProvider.value[i]),this.isExpanded&&this.filterItems(),!1},this.filterItems=()=>{var e=this.itemProvider.value;const t=ObservableLike.getValue(this.props.text||"");let s,i;this.props.filterItems?s=this.props.filterItems(t,e):t?this.props.showTree?([r,l]=filterTreeItems(e,t,[],this.props.filterItem,this.props.filterMatchedItem),s=r,i=l):(s=filterItems(e,t,[],this.props.filterItem),(i=e.findIndex(e=>{return equals(null!=(e=e.text)?e:"",t,!0)}))<0&&(i=e.findIndex(e=>{return startsWith(null!=(e=e.text)?e:"",t,!0)}))):s={filteredItems:e,filteredIndexMap:e.map((e,t)=>t),filterMatches:[]},this.filterMatches=s.filterMatches;var r=this.updateFilteredIndexMap(s.filteredIndexMap),l=(this.filteredItems.value=s.filteredItems,i&&-1<i?i:r);this.focusItem(l),this.isFiltering=!0},this.onKeyDown=e=>{var t,s,i=e.which,r=this.isExpanded;switch(i){case KeyCode.escape:this.isExpanded&&(this.collapse(),e.preventDefault());break;case KeyCode.enter:this.isExpanded||(this.expand(),e.preventDefault());case KeyCode.tab:r&&!e.shiftKey&&(this.filteredItems.length||this.props.allowFreeform)&&(0<=(s=this.getFocusedIndex())?this.selectIndex(s):this.selectedFreeform=!0,this.collapse(),e.preventDefault());break;case KeyCode.upArrow:this.isExpanded&&(this.focusPreviousItem(),this.listBox.current)&&this.listBox.current.scrollIntoView(this.filteredIndexMap.value.indexOf(this.focusedIndex.value),{block:"nearest"}),e.preventDefault();break;case KeyCode.rightArrow:this.isExpanded&&this.props.showTree&&(s=this.getFocusedIndex(),(t=this.itemProvider.value[s]).expanded||(this.props.onToggle&&this.props.onToggle(e,t),this.focusNextItem(),this.focusPreviousItem(),this.listBox.current&&this.listBox.current.scrollIntoView(this.filteredIndexMap.value.indexOf(s),{block:"nearest"})));break;case KeyCode.downArrow:this.isExpanded?(this.focusNextItem(),this.listBox.current&&this.listBox.current.scrollIntoView(this.filteredIndexMap.value.indexOf(this.focusedIndex.value),{block:"nearest"})):this.isExpanded||this.expand(),e.preventDefault();break;case KeyCode.leftArrow:this.isExpanded&&this.props.showTree&&(t=this.getFocusedIndex(),(s=this.itemProvider.value[t]).expanded)&&(this.props.onToggle&&this.props.onToggle(e,s),this.focusPreviousItem(),this.focusNextItem(),this.listBox.current)&&this.listBox.current.scrollIntoView(this.filteredIndexMap.value.indexOf(t),{block:"nearest"});break;case KeyCode.delete:case KeyCode.backspace:this.props.allowClear&&!ObservableLike.getValue(this.props.text||"")?(this.selection.clear(),this.props.onValueChange&&this.props.onValueChange()):this.expand();break;case KeyCode.ctrl:case KeyCode.shift:case void 0:break;default:this.expand()}},this.selection=e.selection||new DropdownSelection,this.itemProvider=new EditableDropdownItemProvider(e.items,this.selection),this.filteredItems=new ObservableArray([...this.itemProvider.value]),this.focusedIndex=new ObservableValue(-1),this.previousFocusedIndex=-1,this.timerManagement=new TimerManagement,this.filteredIndexMap.value=this.itemProvider.value.map((e,t)=>t),this.isFiltering=!1,this.selectSelectedTextItem(),this.props.columns&&(this.columns=this.props.columns.map(r=>Object.assign(Object.assign({},r),{renderCell:(e,t,s,i)=>this.wrapWithFocusedIndexObserver(e,t,s,i,r.renderCell)})))}render(){const{actions:i,allowTextSelection:r,ariaLabel:l,ariaLabelledBy:o,ariaDescribedBy:n,autoSelect:a,calloutContentClassName:d,className:h,disableAutocomplete:c,disabled:p,filterByText:u,getUnselectableRanges:x,inputId:m,noItemsText:I,onToggle:f,selectedText:e,showTree:v,text:t,minCalloutWidth:b,required:g,containerClassName:w}=this.props;return React.createElement(Observer,{text:t,items:{observableValue:this.itemProvider,filter:this.onItemsChange},selection:this.selection,selectedText:e},e=>{let t=this.props.placeholder;var s;return r||(e.selectedText?t=e.selectedText:e.selection.length&&-1<(s=e.selection[0].beginIndex)&&(t=this.itemProvider.value[s].text)),React.createElement(Dropdown,{ariaLabelledBy:o,ariaDescribedBy:n,actions:i,ariaLabel:l,autoSelect:null!==a&&void 0!==a&&a,containerClassName:w,calloutContentClassName:d,className:css("bolt-editable-dropdown",(0<e.selection.length||!!e.selectedText)&&"bolt-editable-dropdown-with-selection",h),columns:this.columns,disableAutocomplete:c,disabled:p,getUnselectableRanges:x,filterByText:u,inputId:m,items:this.itemProvider,noItemsText:I||Resources.NoItemsFound,onCollapse:this.onCollapse,onExpand:this.onExpand,onSelect:this.onSelect,onToggle:f,placeholder:t,ref:this.dropdown,renderCallout:this.renderCallout,renderExpandable:this.renderExpandable,renderItem:this.renderItem,selection:this.selection,showFilterBox:!1,showTree:v,userFilteredItems:this.filteredItems,userFilteredItemsIndexMap:this.filteredIndexMap,minCalloutWidth:b,required:g})})}componentDidMount(){this.props.filterThrottleWait&&(this.filterItems=this.timerManagement.debounce(this.filterItems,this.props.filterThrottleWait))}focus(){this.dropdown.current&&this.dropdown.current.focus()}selectIndex(e){-1<e&&(this.selection.select(e),this.selectedItemInList=!0)}focusItem(e){void 0!==e&&-1<e&&this.isFocusable(e)&&(this.previousFocusedIndex=this.focusedIndex.value,this.focusedIndex.value=e)}updateFilteredIndexMap(e){var t=this.filteredIndexMap.value.indexOf(this.focusedIndex.value);let s=(this.filteredIndexMap.value=e)[t];return this.selection.value.length&&this.selection.value[0].beginIndex===this.selection.value[0].endIndex&&this.selection.selectable(this.selection.value[0].beginIndex)&&-1!==this.filteredIndexMap.value.indexOf(this.selection.value[0].beginIndex)?s=this.selection.value[0].beginIndex:s&&!(s<0)&&this.selection.selectable(s)&&-1!==this.filteredIndexMap.value.indexOf(s)||(s=this.props.showTree?-1:this.filteredIndexMap.value.find(e=>this.selection.selectable(e))),s}focusNextItem(){let t;for(let e=this.filteredIndexMap.value.indexOf(this.focusedIndex.value)+1;e<this.filteredIndexMap.value.length;e++){var s=this.filteredIndexMap.value[e];if(this.selection.selectable(s)&&s>this.focusedIndex.value){t=this.filteredIndexMap.value[e];break}}this.focusItem(t)}focusPreviousItem(){let t;for(let e=this.filteredIndexMap.value.indexOf(this.focusedIndex.value)-1;0<=e;e--)if(this.selection.selectable(this.filteredIndexMap.value[e])){t=this.filteredIndexMap.value[e];break}this.focusItem(t)}getFocusedIndex(){if(!this.props.showTree)return this.focusedIndex.value;let t=this.focusedIndex.value;for(let e=0;e<=Math.min(t,this.itemProvider.value.length-1);e++)isListBoxItemVisible(this.itemProvider.value[e])||this.isFiltering||t++;return t}isFocusable(e){var t;return!this.props.showTree||(t=this.itemProvider.value.filter(e=>isListBoxItemVisible(e)),this.isFiltering?isListBoxItemVisible(this.itemProvider.value[e]):e<t.length)}}CustomEditableDropdown.defaultProps={allowClear:!0,autoAccept:!0,renderExpandable:DropdownExpandableTextField,renderCallout:DropdownCallout,renderItem:renderListBoxCell};export{CustomEditableDropdown};