UNPKG

azure-devops-ui

Version:

React components for building web UI in Azure DevOps

1 lines 13.4 kB
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{ObservableLike,ObservableValue}from"../../Core/Observable";import{FocusWithin}from"../../FocusWithin";import{FocusZone,FocusZoneContext,FocusZoneDirection}from"../../FocusZone";import{IntersectionContext}from"../../Intersection";import{Observer,UncheckedObserver}from"../../Observer";import{css,eventTargetContainsNode,getSafeId,KeyCode}from"../../Util";import{EventDispatch}from"../../Utilities/Dispatch";var FixedHeightList=function(o){function e(e){var c=o.call(this,e)||this,t=(c.intersectionElements={},c.bodyElement=React.createRef(),c.listElement=React.createRef(),c.scrollToIndex=-1,c.scrollToOptions=void 0,c.selectOnFocus=!0,c.focusIndex=new ObservableValue(-1),c.pivotIndex=-1,c.onBlur=function(){c.focusIndex.value=-1},c.onClick=function(e){var t,o;c.onDispatch(e),e.defaultPrevented||c.listElement.current&&(o=(t=rowFromEvent(e)).cellElement,t=t.rowIndex,o||(o=ObservableLike.getValue(c.state.rows[t]),0<=t&&o&&(o={data:o,index:t},c.props.selectRowOnClick&&c.processSelectionEvent(e,o),c.props.singleClickActivation)&&c.rowActivated(e,o)))},c.onDispatch=function(e){c.state.eventDispatch.dispatchEvent(e)},c.onDoubleClick=function(e){var t,o;c.onDispatch(e),e.defaultPrevented||c.props.singleClickActivation||(t=rowFromEvent(e).rowIndex,o=ObservableLike.getValue(c.state.rows[t]),0<=t&&o&&c.rowActivated(e,{data:o,index:t}))},c.onFocusBody=function(e){var t,o;c.selectOnFocus&&((t=c.props.selection)&&!t.selectOnFocus||0<=(t=c.focusIndex.value)&&(o=ObservableLike.getValue(c.state.rows[t]))&&c.processSelectionEvent(e,{data:o,index:t}),c.selectOnFocus=!1)},c.onFocusItem=function(e,t){var o=c.focusIndex;o.value!==e&&(c.focusRow(e,2),0<=o.value?delete c.state.renderedRows[o.value]:void 0!==c.props.defaultTabbableRow&&delete c.state.renderedRows[c.props.defaultTabbableRow],delete c.state.renderedRows[e],c.focusIndex.value=e,o=ObservableLike.getValue(c.state.rows[e]))&&c.rowFocused(t,{data:o,index:e})},c.onKeyDown=function(e){var t,o,i;c.onDispatch(e),e.defaultPrevented||"INPUT"!==(i=e.target.nodeName)&&"TEXTAREA"!==i&&(t=c.focusIndex,o=ObservableLike.getValue(c.state.rows[t.value]))&&(e.which===KeyCode.enter?0<=t.value&&!eventTargetContainsNode(e,["A"])&&c.rowActivated(e,{data:o,index:t.value}):e.which===KeyCode.space?(c.processSelectionEvent(e,{data:o,index:t.value}),e.preventDefault()):e.which===KeyCode.upArrow||e.which===KeyCode.downArrow?(i=c.props.selection)&&(!i.selectOnFocus||!e.shiftKey&&e.ctrlKey)||(e.persist(),window.setTimeout(function(){c.focusIndex.value!=t.value&&c.processSelectionEvent(e,{data:o,index:c.focusIndex.value})},0)):e.which===KeyCode.pageDown?(c.focusRow(Math.min(t.value+c.props.pageSize,c.state.rowCount-1),1),e.preventDefault()):e.which===KeyCode.pageUp?(c.focusRow(Math.max(t.value-c.props.pageSize,0),-1),e.preventDefault()):e.which===KeyCode.home?(c.focusRow(0,1),e.preventDefault()):e.which===KeyCode.end&&(c.focusRow(c.state.rowCount-1,-1),e.preventDefault()))},c.onIntersect=function(e){var t,o,i=c.context.root.scrollTop,r=c.state.rowCount,n=c.state,s=n.firstMaterialized,n=n.lastMaterialized,a=c.state,l=a.rowHeight,a=a.rowProportion;i!==c.state.scrollTop&&e.length||c.listElement.current&&c.bodyElement.current&&(e=c.context.root.getBoundingClientRect(),t=Math.max(0,i+c.context.root.offsetTop-c.listElement.current.offsetTop),a=Math.max(0,Math.min(r-1,Math.floor(t/(l*a)))),t+((o=Math.min(r-1,a+Math.ceil(e.height/l)))-a)*l>c.state.maxHeight&&(o=r-1,a=Math.max(0,o-Math.ceil(e.height/l))),a===s&&o===n&&l===c.state.rowHeight&&i===c.state.scrollTop&&t===c.state.scrollTopRect||c.setState({firstMaterialized:a,lastMaterialized:o,rowHeight:l,scrollTop:i,scrollTopRect:t}))},c.onMouseDownBody=function(e){c.selectOnFocus=!1},e.itemProvider.length);return c.state={eventDispatch:e.eventDispatch||new EventDispatch,firstMaterialized:0,itemProvider:e.itemProvider,lastMaterialized:0,maxHeight:c.props.maxHeight||1e6,focusRows:{},renderedRows:{},rowCount:t,rowHeight:e.rowHeight||0,rowProportion:e.rowHeight&&e.maxHeight?Math.min(1,e.maxHeight/(e.rowHeight*t)):1,rows:{},scrollTop:0,scrollTopRect:0},c}return __extends(e,o),e.getDerivedStateFromProps=function(e,t){var o=e.itemProvider.length,i=t.firstMaterialized,r=t.lastMaterialized,i=(o!==t.rowCount&&(i=Math.max(0,Math.min(t.firstMaterialized,o)),r=Math.max(i,Math.min(t.lastMaterialized+(t.lastMaterialized===t.rowCount-1?e.pageSize:0),o-1))),{firstMaterialized:i,itemProvider:e.itemProvider,lastMaterialized:r,rowCount:o,rowProportion:Math.min(1,t.maxHeight/(t.rowHeight*o))});return e.itemProvider!==t.itemProvider&&(i.renderedRows={},i.rows={}),i},e.prototype.getListRole=function(){return this.props.role||(this.props.selection?"listbox":"list")},e.prototype.getItemRole=function(){switch(this.getListRole()){case"tree":case"group":return"treeitem";case"list":return"listitem";case"listbox":return"option";case"radiogroup":return"radio";default:return null}},e.prototype.render=function(){var i=this,e=this.props,t=e.className,o=e.focuszoneProps,r=e.id,e=e.width,n=this.state,s=n.firstMaterialized,a=n.lastMaterialized,l=n.maxHeight,c=n.rowCount,n=n.rowHeight,d=this.getListRole(),u=[],h=Math.max(0,this.focusIndex.value-3),p=Math.min(c,this.focusIndex.value+3);if(u.push(this.renderIntersectionBounds(!0)),-1!==this.focusIndex.value&&h<s)for(var m=h;m<=Math.min(p,s-1);m++)u.push(this.renderRow(m,!1));for(m=s;m<=a;m++)u.push(this.renderRow(m,!0));if(-1!==this.focusIndex.value&&a<p&&0<a)for(m=Math.max(h,a+1);m<=p;m++)u.push(this.renderRow(m,!1));u.push(this.renderIntersectionBounds(!1));var c=Math.min(l,n*this.state.rowCount),v=React.createElement("div",{"aria-label":this.props.ariaLabel,className:css(t,"bolt-fixed-height-list relative"),id:getSafeId(r),onBlur:this.onBlur,onClick:this.onClick,onDoubleClick:this.onDoubleClick,onDragEnd:this.onDispatch,onDragEnter:this.onDispatch,onDragExit:this.onDispatch,onDragOver:this.onDispatch,onDragStart:this.onDispatch,onDrop:this.onDispatch,onKeyUp:this.onDispatch,onMouseDown:this.onDispatch,onTouchStart:this.onDispatch,ref:this.listElement,role:d,style:{width:e,height:c}},React.createElement("div",{className:"relative",onFocus:this.onFocusBody,onKeyDown:this.onKeyDown,onMouseDown:this.onMouseDownBody,ref:this.bodyElement,style:{width:e,height:c}},u)),v=React.createElement(FocusZone,__assign({direction:FocusZoneDirection.Vertical,skipHiddenCheck:!0},o),v);return React.createElement(Observer,{itemProvider:{filter:function(e,t){i.props.selection&&i.props.selection.onItemsChanged(e,t);var o,t={renderedRows:{},focusRows:{},rows:{}};return-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=Math.max(t.firstMaterialized,Math.min(i.state.lastMaterialized+(e.index>=i.state.firstMaterialized&&e.index<=i.state.lastMaterialized+1?o:0),t.rowCount-1))),i.setState(t),!1},observableValue:this.props.itemProvider}},function(){return v})},e.prototype.componentDidMount=function(){this.onIntersect([]),this.context.register(this.onIntersect)},e.prototype.componentDidUpdate=function(e,t){var o=this.scrollToIndex,i=this.onScrollComplete;if(this.state.rowCount!==t.rowCount&&this.onIntersect([]),-1!==o&&this.state.rowHeight){var r=this.bodyElement.current,t=this.state,n=t.firstMaterialized,t=t.lastMaterialized;if(n<=o&&o<=t&&r)for(var s=0;s<r.children.length;s++){var a=r.children[s];if(rowFromElement(a).rowIndex===o){a.scrollIntoView(this.scrollToOptions);break}}this.onScrollComplete=void 0,this.scrollToIndex=-1,this.scrollToOptions=void 0,i&&i(o)}},e.prototype.componentWillUnmount=function(){this.context.unregister(this.onIntersect)},e.prototype.getFocusIndex=function(){return this.focusIndex.value},e.prototype.getStats=function(){return{firstMaterialized:this.state.firstMaterialized,lastMaterialized:this.state.lastMaterialized}},e.prototype.scrollIntoView=function(e,t,o){this.props.pageSize;var i=this.state,r=i.firstMaterialized,n=i.lastMaterialized,i=i.rowCount;if(0<=e&&e<this.state.rowCount){var s=this.bodyElement.current;if(r<=e&&e<=n&&s){for(var a=0;a<s.children.length;a++){var l=s.children[a];if(rowFromElement(l).rowIndex===e){l.scrollIntoView(t);break}}o&&o(e)}else this.onScrollComplete&&this.onScrollComplete(-1),this.onScrollComplete=o,this.scrollToIndex=e,this.scrollToOptions=t,this.setState({firstMaterialized:Math.max(0,e-Math.floor((n-r)/2)),lastMaterialized:Math.min(i-1,Math.ceil(e+(n-r)/2))})}},e.prototype.focusRow=function(o,i){var r=this;this.scrollIntoView(o,{block:"nearest"},function(e){var t;e===o&&r.bodyElement.current&&(t=r.bodyElement.current.querySelector("[data-row-index='"+e+"']"))&&(t.getAttribute("tabindex")?t.focus():(t=Math.min(r.state.rowCount-1,Math.max(0,e+i)))!==e?r.focusRow(t,i):t!==r.focusIndex.value&&r.focusRow(t,-i))})},e.prototype.processSelectionEvent=function(e,t){var o,i,r,n=this.props.selection;n&&!n.selectable(t.index)||(o=!(r=!1),n&&(i=t.index,r=n.selected(i),0<=this.pivotIndex&&e.shiftKey&&n.multiSelect?n.select(Math.min(this.pivotIndex,i),Math.abs(this.pivotIndex-i)+1,e.ctrlKey||e.metaKey):(e.ctrlKey||e.metaKey||n.alwaysMerge)&&n.multiSelect?(n.toggle(i,!0),o=!1):n.select(i,1,!1),e.shiftKey||(this.pivotIndex=i)),r!==o&&this.rowSelected(e,t))},e.prototype.renderLoadingRow=function(e,t){return React.createElement("div",{className:"bolt-list-row-loading"},React.createElement("div",{className:"shimmer shimmer-line",style:{width:80*Math.random()+20+"%"}}," "))},e.prototype.renderIntersectionBounds=function(e){var o=this,t=this.state,i=t.firstMaterialized,r=t.lastMaterialized,n=t.rowHeight,t=t.rowProportion,s=e?"topobserv":"bottomobserv",a=0;return i*n*t+(r-i)*n>this.state.maxHeight?e?(a=this.state.maxHeight,a-=(r-i)*n*t+n,a--):a=this.state.maxHeight-1:a=e?i*n*t-1:i*n*t+(1+r-i)*n+1,React.createElement("div",{className:"bolt-list-row-spacer invisible absolute",key:s,ref:function(e){var t=o.intersectionElements[s];e?t!==e&&(t&&o.context.unobserve(e),o.context.observe(e),o.intersectionElements[s]=e):t&&(o.context.unobserve(t),delete o.intersectionElements[s])},role:"presentation",style:{top:"".concat(a,"px"),height:"1px"}})},e.prototype.renderRow=function(u,e){var h=this,t=this.props.itemProvider,o=this.state,i=o.focusRows,r=o.renderedRows,p=o.firstMaterialized,m=o.lastMaterialized,v=(o.rowHeight,o.rowProportion),o=o.rows,f=this.getItemRole();if(!(r=(e?r:i)[u])||1!==v){var w=o[u];if(!(w=w||(t.getItem?t.getItem(u):t.value[u])))return null;o[u]=w;function x(e){h.onFocusItem(u,e)}i=this.props.selection,t=void 0,r=React.createElement(UncheckedObserver,{item:w,key:u,selection:t=i?{observableValue:i,filter:function(e){for(var t=0,o=e;t<o.length;t++){var i=o[t];if(u>=i.beginIndex&&u<=i.endIndex)return!0}return!1}}:t,focusIndex:this.focusIndex},function(e){var t=h.props,o=t.renderRow,t=t.renderLoadingRow,i=h.state,r=i.rowHeight,i=i.rowCount,n=ObservableLike.getValue(w),n={ariaBusy:!e.item,ariaRowOffset:1,data:n,eventDispatch:h.state.eventDispatch,itemProvider:h.props.itemProvider,listProps:h.props,onFocusItem:h.onFocusItem,singleClickActivation:h.props.onActivate&&h.props.singleClickActivation},s=e.item?o(u,e.item,n):t?t(u,n):h.renderLoadingRow(u,n),a=0,l=p<=u&&u<=m?r:0,o=(p*r*v+(m-p)*r>h.state.maxHeight?a=(a=h.state.maxHeight)-(i-m)*r*v-(m-u)*r:0===l?a=u*r*v:(a=p*r*v,a+=(u-p)*r),null===n?void 0:n.data),c=null==(e=null==o?void 0:o.underlyingItem)?void 0:e.childItems,d=null==(t=null==o?void 0:o.underlyingItem)?void 0:t.expanded;return React.createElement(FocusWithin,{onFocus:x},function(t){return React.createElement(FocusZoneContext.Consumer,null,function(e){return React.createElement(FocusZone,{direction:FocusZoneDirection.Horizontal},React.createElement("div",{className:css("bolt-fixed-height-list-row scroll-hidden absolute",h.focusIndex.value===u&&"focused"),style:{height:"".concat(l,"px"),top:"".concat(a,"px")},"data-focuszone":e.focuszoneId,"data-row-index":u,tabIndex:0==u||c?0:-1,onBlur:t.onBlur,onFocus:t.onFocus,role:f,"aria-expanded":(!c||void 0!==d)&&d,"aria-labelledby":"rowContent-".concat(u)},s))})})});e?this.state.renderedRows[u]=r:this.state.focusRows[u]=r}return r},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={defaultTabbableRow:0,focuszoneProps:{direction:FocusZoneDirection.Vertical},maxHeight:1e6},e}(React.Component);function getAttributeAsNumber(e,t){e=e.getAttribute(t);return e?parseInt(e,10):-1}function rowFromElement(e){for(var t,o=-1;e;){if(-1!==(t=getAttributeAsNumber(e,"data-row-index"))){o=t;break}if(e.classList.contains("bolt-fixed-height-list")){e=null;break}e=e.parentElement}return{cellElement:null,cellIndex:-1,rowElement:e,rowIndex:o}}function rowFromEvent(e){return rowFromElement(e.target)}export{FixedHeightList,rowFromElement,rowFromEvent};