azure-devops-ui
Version:
React components for building web UI in Azure DevOps
1 lines • 19.1 kB
JavaScript
import{__assign,__extends}from"tslib";import"../../CommonImports";import"../../Core/core.css";import"./DropdownList.css";import"./List.css";import"./ListDropIndicator.css";import*as React from"react";import*as Utils_Accessibility from"../../Core/Util/Accessibility";import{ObservableArray,ObservableLike}from"../../Core/Observable";import{FocusWithin}from"../../FocusWithin";import{FocusZone,FocusZoneContext,FocusZoneDirection}from"../../FocusZone";import{IntersectionContext}from"../../Intersection";import{getDefaultLinkProps}from"../../Link";import{Observer,UncheckedObserver}from"../../Observer";import*as Resources from"../../Resources.Widgets";import{css,eventTargetContainsNode,getSafeId,KeyCode}from"../../Util";import{EventDispatch}from"../../Utilities/Dispatch";import{getDragInProgress}from"../../Utilities/DragDrop";import{getTabIndex}from"../../Utilities/Focus";var DropdownList=function(a){function e(e){var E=a.call(this,e)||this,t=(E.bodyElement=React.createRef(),E.listElement=React.createRef(),E.spacerElements={},E.scrollToIndex=-1,E.scrollToOptions=void 0,E.selectOnFocus=!0,E.focusIndex=-1,E.pivotIndex=-1,E.onVirtualizeKeyDown=function(e){E.state.virtualize&&e.ctrlKey&&e.altKey&&"v"===e.key&&(e=E.props.itemProvider.length,E.setState({virtualize:!1,lastMaterialized:e-1,lastRendered:e-1,firstMaterialized:0,firstRendered:0}),Utils_Accessibility.announce(Resources.VirtualizationDisabled))},E.onBlur=function(){E.focusIndex=-1},E.onClick=function(e){var t,o;E.onDispatch(e),e.defaultPrevented||e.altKey&&E.props.selectableText||E.listElement.current&&(o=(t=cellFromEvent(e)).cellElement,t=t.rowIndex,o&&eventTargetContainsNode(e,["A"],o)||(o=ObservableLike.getValue(E.state.rows[t]),0<=t&&o&&(o={data:o,index:t},E.props.selectRowOnClick&&E.processSelectionEvent(e,o),E.props.singleClickActivation)&&E.rowActivated(e,o)))},E.onDispatch=function(e){E.state.eventDispatch.dispatchEvent(e)},E.onDoubleClick=function(e){var t,o;E.onDispatch(e),e.defaultPrevented||E.props.singleClickActivation||(t=cellFromEvent(e).rowIndex,o=ObservableLike.getValue(E.state.rows[t]),0<=t&&o&&E.rowActivated(e,{data:o,index:t}))},E.onFocusBody=function(e){var t,o;E.selectOnFocus&&((t=E.props.selection)&&!t.selectOnFocus||0<=(t=E.focusIndex)&&(o=ObservableLike.getValue(E.state.rows[t]))&&E.processSelectionEvent(e,{data:o,index:t}),E.selectOnFocus=!1)},E.onFocusItem=function(e,t){var o=E.focusIndex;o!==e&&(0<=o?delete E.state.renderedRows[o]:delete E.state.renderedRows[E.getInitialTabbableRow()],delete E.state.renderedRows[e],E.focusIndex=e,o=ObservableLike.getValue(E.state.rows[e]))&&E.rowFocused(t,{data:o,index:e})},E.onKeyDown=function(t){var o,e,i;E.onDispatch(t),t.defaultPrevented||"INPUT"!==(e=t.target.nodeName)&&"TEXTAREA"!==e&&(o=E.focusIndex,e=ObservableLike.getValue(E.state.rows[o]))&&(t.which===KeyCode.enter?0<=o&&!eventTargetContainsNode(t,["A"])&&E.rowActivated(t,{data:e,index:o}):t.which===KeyCode.space?(E.processSelectionEvent(t,{data:e,index:o}),t.preventDefault()):t.which===KeyCode.upArrow||t.which===KeyCode.downArrow?(e=E.props.selection)&&(!e.selectOnFocus||!t.shiftKey&&t.ctrlKey)||(t.persist(),window.setTimeout(function(){var e;E.focusIndex!=o&&(e=ObservableLike.getValue(E.state.rows[E.focusIndex]))&&E.processSelectionEvent(t,{data:e,index:E.focusIndex})},0)):t.which===KeyCode.pageDown?(i=E.getStats(),E.focusRow(Math.min(o+(i.lastRendered-i.firstRendered),E.state.rowCount-1),1),t.preventDefault()):t.which===KeyCode.pageUp?(i=E.getStats(),E.focusRow(Math.max(o-(i.lastRendered-i.firstRendered),0),-1),t.preventDefault()):t.which===KeyCode.home?(E.focusRow(0,1),t.preventDefault()):t.which===KeyCode.end&&(E.focusRow(E.state.rowCount-1,-1),t.preventDefault()))},E.onIntersect=function(e){if(E.state.virtualize){var t=E.context.root.scrollTop,o=E.state,i=o.firstRendered,r=o.firstMaterialized,n=o.lastRendered,a=o.lastMaterialized,s=o.rowCount,l=o.rowProportion,c=E.state.rowHeight;if((t===E.state.scrollTop||!e.length)&&E.listElement.current&&E.bodyElement.current){var d=E.bodyElement.current.children;if(0===c){if(0<d.length){for(var u=0,p=0,h=0;h<d.length;h++){var m=E.bodyElement.current.children[h].getBoundingClientRect().height;0<m&&(u+=m,p++)}0<p&&(c=u/p)}if(0===c)return;if(-1!==E.scrollToIndex)return void E.setState({firstMaterialized:Math.max(0,E.scrollToIndex-E.state.pageSize),lastMaterialized:E.scrollToIndex+Math.min(E.props.initialPageCount*E.state.pageSize,s-1),rowHeight:c})}for(var f,v,g,w,b=E.context.root.getBoundingClientRect(),x=r,y=a,I=y,R=x,h=0;h<d.length;h++){var M=d[h],z=getAttributeAsNumber(M,"data-row-index"),C=M.getBoundingClientRect();r<=z&&z<=a&&(C.bottom<b.top-E.state.pageSize*(l*c)?x++:C.top>b.bottom+E.state.pageSize*(l*c)&&y--,z===r&&(f=M),z===a)&&(v=M),-1<z&&C.top<b.bottom&&C.bottom>b.top&&(R=Math.max(R,z),I=Math.min(I,z))}l<1?y<x||I===x||R===y?s-1<=R?x=Math.ceil(y-(b.height/c+E.state.pageSize)):(g=t-(E.listElement.current.offsetTop-E.context.root.offsetTop),x=Math.max(0,Math.min(s-1,Math.floor(g/(l*c)))-E.state.pageSize),y=Math.min(s-1,x+Math.ceil(b.height/(l*c)+E.state.pageSize-1)),I=R=-1):(x=Math.min(x,I-E.state.pageSize),y=Math.max(y,R+E.state.pageSize-1),I=R=-1):y<x?(g=t-(E.listElement.current.offsetTop-E.context.root.offsetTop),x=Math.max(0,Math.min(s-1,Math.floor(g/c))-E.state.pageSize),y=Math.min(s-1,x+Math.ceil(b.height/c+E.state.pageSize-1)),I=R=-1):(x===r&&f&&0<(w=(C=f.getBoundingClientRect()).top-b.top)&&(x-=Math.ceil(w/c)),y===a&&v&&(C=v.getBoundingClientRect(),0<(w=b.bottom-C.bottom))&&(y+=Math.ceil(w/c))),x=Math.max(x,0),y=Math.min(y,s-1),x===r&&I===i&&y===a&&R===n&&c===E.state.rowHeight&&t===E.state.scrollTop||E.setState({firstMaterialized:x,firstRendered:I,lastMaterialized:y,lastRendered:R,rowHeight:c,scrollTop:t})}}},E.onPointerDownBody=function(e){E.selectOnFocus=!1},E.getInitialTabbableRow=function(){var e=E.props,t=e.defaultTabbableRow,o=e.itemProvider,i=e.selection;if(t)return t;if(i)for(var r=0;r<o.length;r++)if(i.selectable(r))return r;return 0},E.getHeight=function(e,t){for(var o=0,i=E.props.rowHeights||[],r=t?E.state.rowCount-e:0,n=t?E.state.rowCount:e,a=r;a<n;a++)o+=i[a]||E.state.rowHeight;return o},e.itemProvider.length),o=e.pageSize;if(E.state={columnCount:1,eventDispatch:e.eventDispatch||new EventDispatch,firstMaterialized:0,firstRendered:0,itemProvider:e.itemProvider,lastMaterialized:E.props.virtualize?Math.min(e.initialPageCount*o,t-1):t-1,lastRendered:E.props.virtualize?Math.min(e.initialPageCount*o,t-1):t-1,overlays:new ObservableArray,pageSize:o,renderedRows:{},rowCount:t,rowHeight:e.rowHeight||0,rowProportion:e.rowHeight&&e.maxHeight?Math.min(1,e.maxHeight/(e.rowHeight*t)):1,rows:{},scrollTop:0,virtualize:!!e.virtualize},e.behaviors)for(var i=0,r=e.behaviors;i<r.length;i++){var n=r[i];n.initialize&&n.initialize(e,E,E.state.eventDispatch)}return E}return __extends(e,a),e.getDerivedStateFromProps=function(e,t){var o=e.itemProvider.length,i=t.firstMaterialized,r=t.lastMaterialized,o=(o!==t.rowCount&&(i=Math.max(0,Math.min(t.firstMaterialized,o)),r=t.virtualize?Math.max(i,Math.min(t.lastMaterialized+(t.lastMaterialized===t.rowCount-1||t.lastMaterialized===t.rowCount?e.pageSize:0),o-1)):o-1),{firstMaterialized:i,itemProvider:e.itemProvider,lastMaterialized:r,pageSize:e.pageSize,rowCount:o,rowProportion:Math.min(1,(e.maxHeight||1e5)/(t.rowHeight*(o-(r-i))))});return e.itemProvider===t.itemProvider&&e.columnCount===t.columnCount||(o.columnCount=e.columnCount,o.renderedRows={},o.rows={}),o},e.prototype.render=function(){var i=this,e=this.props,t=e.ariaRowOffset,o=e.className,r=e.focuszoneProps,n=e.id,a=e.maxWidth,s=e.minWidth,l=e.width,e=this.state,c=e.firstMaterialized,d=e.lastMaterialized,u=e.rowCount,e=e.rowProportion,p=this.focusIndex,h=this.props.role||(this.props.selection?"listbox":"list"),m="table"===h||"grid"===h||"treegrid"===h,f=[],v=0,g=c,w=Math.max(0,u-d-1),b=0,x=Number.MAX_SAFE_INTEGER,y=0;if(-1!==p&&(x=Math.max(0,p-3),y=Math.min(u,p+3),x<c?(v=x,g=c-(y=Math.min(y,c-1))-1):d<y&&(w=(x=Math.max(x,d+1))-d-1,b=Math.max(0,u-y-1))),e<1&&(g+=Math.min(this.state.pageSize,c)),f.push(this.renderSpacer("st1",v)),x<c)for(var I=x;I<=y;I++)f.push(this.renderRow(I));f.push(this.renderSpacer("st2",g));for(I=c;I<=d;I++)f.push(this.renderRow(I));if(f.push(this.renderSpacer("sb2",w,{countFromBottom:!0,estimateRowHeight:!this.props.rowHeights})),d<y)for(I=x;I<=y;I++)f.push(this.renderRow(I));return f.push(this.renderSpacer("sb1",b,{countFromBottom:!0,estimateRowHeight:!this.props.rowHeights})),React.createElement(UncheckedObserver,{itemProvider:{filter:function(e,t){i.props.selection&&i.props.selection.onItemsChanged(e,t);var o,t={renderedRows:{},rows:{}};return e.removedItems&&i.focusIndex>=e.index&&e.index+e.removedItems.length>=i.focusIndex&&(i.focusIndex=-1),-1!==i.state.rowCount&&(o=(e.addedItems?e.addedItems.length:0)-(e.removedItems?e.removedItems.length:0))&&(t.rowCount=i.state.rowCount+o,t.firstMaterialized=Math.max(0,Math.min(i.state.firstMaterialized,t.rowCount-1)),t.lastMaterialized=i.state.virtualize?Math.max(t.firstMaterialized,Math.min(i.state.lastMaterialized+(e.index>=i.state.firstMaterialized&&e.index<=i.state.lastMaterialized+1?Math.min(i.state.pageSize,o):0),t.rowCount-1)):t.rowCount-1),i.setState(t),!1},observableValue:this.props.itemProvider}},React.createElement(FocusWithin,{onBlur:this.onBlur},function(e){e=React.createElement("ul",{"aria-colcount":m?i.props.ariaColumnCount||i.props.columnCount:void 0,"aria-label":i.props.ariaLabel,"aria-rowcount":m?i.state.itemProvider.length+t:void 0,className:css(o,"bolt-list body-m relative",i.props.showScroll?void 0:"scroll-hidden"),id:getSafeId(n),onBlur:e.onBlur,onClick:i.onClick,onContextMenu:i.onDispatch,onDoubleClick:i.onDoubleClick,onDragEnd:i.onDispatch,onDragEnter:i.onDispatch,onDragExit:i.onDispatch,onDragOver:i.onDispatch,onDragStart:i.onDispatch,onDrop:i.onDispatch,onFocus:e.onFocus,onKeyDown:i.onKeyDown,onKeyUp:i.onDispatch,onPointerDown:i.onDispatch,ref:i.listElement,role:h,style:{maxWidth:a,minWidth:s,width:l},tabIndex:0},i.props.renderHeader&&i.props.renderHeader(),React.createElement("div",{className:css("relative","listbox"),onFocus:i.onFocusBody,onPointerDown:i.onPointerDownBody,ref:i.bodyElement,role:"listbox"===h||"list"===h||"menu"===h||"tree"===h?"presentation":void 0},i.renderOverlay(i.listElement),f));return e=r?React.createElement(FocusZone,__assign({},r,{skipHiddenCheck:!0}),e):e}))},e.prototype.componentDidMount=function(){this.context.register(this.onIntersect),this.props.virtualize&&document.addEventListener("keydown",this.onVirtualizeKeyDown)},e.prototype.componentDidUpdate=function(){var e=this.scrollToIndex,t=this.onScrollComplete;if(-1!==e&&this.state.rowHeight){var o=this.bodyElement.current,i=this.state,r=i.firstMaterialized,i=i.lastMaterialized;if(r<=e&&e<=i&&o)for(var n=0;n<o.children.length;n++){var a=o.children[n];if(cellFromElement(a).rowIndex===e){a.scrollIntoView(this.scrollToOptions);break}}this.onScrollComplete=void 0,this.scrollToIndex=-1,this.scrollToOptions=void 0,t&&t(e)}},e.prototype.componentWillUnmount=function(){this.context.unregister(this.onIntersect),this.props.virtualize&&document.removeEventListener("keydown",this.onVirtualizeKeyDown)},e.prototype.addOverlay=function(t,e,o,i,r){void 0===i&&(i=0);var n=this.state.overlays,a=n.value.findIndex(function(e){return e.id===t}),o={render:o,id:t,rowIndex:e,zIndex:i+1,columnIndex:r};0<=a?n.change(a,o):n.push(o)},e.prototype.removeOverlay=function(t){var e=this.state.overlays,o=e.value.findIndex(function(e){return e.id===t});0<=o&&e.splice(o,1)},e.prototype.getFocusIndex=function(){return this.focusIndex},e.prototype.getStats=function(){return{firstMaterialized:this.state.firstMaterialized,firstRendered:this.state.firstRendered,lastMaterialized:this.state.lastMaterialized,lastRendered:this.state.lastRendered}},e.prototype.scrollIntoView=function(e,t,o){var i=this.state,r=i.firstMaterialized,n=i.lastMaterialized,a=i.pageSize,s=i.rowCount,l=i.rowHeight,i=i.rowProportion;if(0<=e&&e<this.state.rowCount){var c=this.bodyElement.current;if(r<=e&&e<=n&&c){for(var d=0;d<c.children.length;d++){var u=c.children[d];if(cellFromElement(u).rowIndex===e){u.scrollIntoView(t);break}}o&&o(e)}else{this.onScrollComplete&&this.onScrollComplete(-1),this.onScrollComplete=o,this.scrollToIndex=e,this.scrollToOptions=t;r=i<1?a:0;l&&this.setState({firstMaterialized:Math.max(0,e-r),lastMaterialized:Math.min(s-1,e+r)})}}},e.prototype.focusRow=function(i,r){var n=this;return void 0===r&&(r=1),new Promise(function(o){n.scrollIntoView(i,{block:"center"},function(e){var t;e===i&&n.bodyElement.current&&(t=n.bodyElement.current.querySelector("[data-row-index='"+e+"']"))&&(t.getAttribute("tabindex")?t.focus():(t=Math.min(n.state.rowCount-1,Math.max(0,e+r)))!==e?n.focusRow(t,r):t!==n.focusIndex&&n.focusRow(t,-r)),o()})})},e.prototype.processSelectionEvent=function(e,t){var o,i,r=this.props,n=r.selection,r=r.enforceSingleSelect;n&&!n.selectable(t.index)||(n&&(o=t.index,r=!r&&n.multiSelect,0<=this.pivotIndex&&e.shiftKey&&r?n.select(Math.min(this.pivotIndex,o),Math.abs(this.pivotIndex-o)+1,e.ctrlKey||e.metaKey,r):(i=e.which===KeyCode.space,(e.ctrlKey||e.metaKey||n.alwaysMerge||i)&&r?n.toggle(o,!0,r):n.select(o,1,!1,r)),e.shiftKey||(this.pivotIndex=o)),this.rowSelected(e,t))},e.prototype.renderLoadingRow=function(e,t){return React.createElement(DropdownListItem,{className:"bolt-list-row-loading",details:t,index:e},React.createElement("div",{className:"shimmer shimmer-line",style:{width:80*Math.random()+20+"%"}}," "))},e.prototype.renderOverlay=function(r){var n=this,e=this.state,a=e.firstMaterialized,s=e.lastMaterialized,e=e.overlays;return React.createElement(Observer,{overlays:e},function(e){var i=n.bodyElement.current;return 0<e.overlays.length&&i?React.createElement("div",{className:"bolt-list-overlay-container absolute"},e.overlays.map(function(e){var t,o;return(-1===e.rowIndex||!(e.rowIndex<a||e.rowIndex>s)||getDragInProgress())&&(t=r.current&&r.current.querySelector("[data-row-index='"+e.rowIndex+"']"),t=n.props.overlay?null==t?void 0:t.querySelector(n.props.overlay):t,o=null==(o=r.current)?void 0:o.querySelector("[data-column-index='"+e.columnIndex+"']"),t)?o?React.createElement("div",{className:"bolt-list-overlay flex-row absolute",id:getSafeId(e.id),key:e.id,style:{height:t.offsetHeight,width:o.offsetWidth,top:t.getBoundingClientRect().top-i.getBoundingClientRect().top,left:o.getBoundingClientRect().left-i.getBoundingClientRect().left,zIndex:10*e.zIndex}},e.render({rowElement:o})):React.createElement("div",{className:"bolt-list-overlay flex-row absolute",id:getSafeId(e.id),key:e.id,style:{height:t.offsetHeight,top:t.getBoundingClientRect().top-i.getBoundingClientRect().top,zIndex:10*e.zIndex}},e.render({rowElement:t})):null})):null})},e.prototype.renderRow=function(a){var s=this,e=this.props.itemProvider,t=this.state,o=t.renderedRows,t=t.rows;if(!(o=o[a])){var l=t[a];if(!(l=l||(e.getItem?e.getItem(a):e.value[a])))return null;t[a]=l;e=this.props.selection,t=e?{observableValue:e,filter:function(e){for(var t=0,o=e;t<o.length;t++){var i=o[t];if(a>=i.beginIndex&&a<=i.endIndex)return!0}return!1}}:void 0,o=React.createElement(UncheckedObserver,{item:l,key:a,selection:t},function(e){var t=s.props,o=t.selectableText,i=t.renderRow,t=t.renderLoadingRow,r=s.focusIndex,r=0<=r?r:s.getInitialTabbableRow(),n=ObservableLike.getValue(l),o={selectableText:o,ariaBusy:!e.item,ariaRowOffset:s.props.ariaRowOffset+1,data:n,eventDispatch:s.state.eventDispatch,excludeTabStop:s.props.excludeTabStop||r!==a,listProps:s.props,onFocusItem:s.onFocusItem,singleClickActivation:s.props.onActivate&&s.props.singleClickActivation};return e.item?i(a,e.item,o):t?t(a,o):s.renderLoadingRow(a,o)});this.state.renderedRows[a]=o}return o},e.prototype.renderSpacer=function(o,e,t){var i=this,r=null!=t&&t.estimateRowHeight||null==(r=this.props.rowHeights)||!r.length?e*this.state.rowHeight*this.state.rowProportion:this.getHeight(e,null==t?void 0:t.countFromBottom);return React.createElement("div",{className:"bolt-list-row-spacer invisible",key:o,ref:function(e){var t=i.spacerElements[o];e?t!==e&&(t&&i.context.unobserve(e),i.context.observe(e),i.spacerElements[o]=e):t&&(i.context.unobserve(t),delete i.spacerElements[o])},role:"presentation"},React.createElement("div",{className:"bolt-list-cell-spacer invisible",style:{height:r+"px"}}))},e.prototype.rowActivated=function(e,t){this.state.eventDispatch.dispatchEvent(e,t,"activate"),this.props.onActivate&&this.props.onActivate(e,t)},e.prototype.rowSelected=function(e,t){this.state.eventDispatch.dispatchEvent(e,t,"select"),this.props.onSelect&&this.props.onSelect(e,t)},e.prototype.rowFocused=function(e,t){this.state.eventDispatch.dispatchEvent(e,t,"focus"),this.props.onFocus&&this.props.onFocus(e,t)},e.contextType=IntersectionContext,e.defaultProps={ariaRowOffset:0,columnCount:1,focuszoneProps:{direction:FocusZoneDirection.Vertical},initialPageCount:3,maxHeight:1e5,pageSize:10,singleClickActivation:!1,selectRowOnClick:!0,virtualize:!0},e}(React.Component);function DropdownListItem(o){var i=o.children,r=o.details,n=o.index,a=o.linkProps,s=o.itemId,l=o.tabIndex,c=r.selectableText,d=r.ariaBusy,u=r.ariaDescribedBy,p=r.ariaLabel,h=r.ariaPosInSet,m=r.ariaSetSize,f=r.excludeFocusZone,e=r.listProps,v=e.selection,g=e.singleClickActivation;return React.createElement(FocusWithin,{onFocus:function(e){o.details.onFocusItem(o.index,e)}},function(t){return React.createElement(FocusZoneContext.Consumer,null,function(e){e={"aria-busy":d,"aria-describedby":u,"aria-label":p,"aria-posinset":void 0===h?n+1:null===h?void 0:h,"aria-selected":v&&v.selected(n),"aria-setsize":void 0===m?o.details.listProps.itemProvider.length:null===m?void 0:m,className:css(o.className,"bolt-list-row",0===n&&"first-row",a&&"bolt-link",v&&v.selected(n)&&"selected",t.hasFocus&&"focused",g&&"single-click-activation",c&&"selectable-text"),"data-focuszone":f||v&&!v.selectable(n)?void 0:e.focuszoneId,"data-row-index":n,"data-itemid":s,tabIndex:null!=l?l:getTabIndex(r),onBlur:t.onBlur,onFocus:t.onFocus,role:v?"option":"listitem"};return React.createElement(FocusZone,{direction:FocusZoneDirection.Horizontal},a?React.createElement("a",__assign({},getDefaultLinkProps(a),e),React.createElement("div",{className:"bolt-list-cell","data-column-index":0},React.createElement("div",{className:"bolt-list-cell-content flex-row"},i))):React.createElement("li",__assign({},e),React.createElement("span",{className:"bolt-list-cell","data-column-index":0},React.createElement("div",{className:"bolt-list-cell-content flex-row"},i))))})})}function getAttributeAsNumber(e,t){e=e.getAttribute(t);return e?parseInt(e,10):-1}function cellFromElement(e){for(var t,o=-1,i=-1,r=null;e;){if(-1!==(t=getAttributeAsNumber(e,"data-column-index"))&&(o=t,r=e),-1!==(t=getAttributeAsNumber(e,"data-row-index"))){i=t;break}if(e.classList.contains("bolt-list")){e=null;break}e=e.parentElement}return{cellElement:r,cellIndex:o,rowElement:e,rowIndex:i}}function cellFromEvent(e){return cellFromElement(e.target)}export{DropdownList,DropdownListItem};