@blueprintjs/select
Advanced tools
Comparing version 3.13.6 to 3.13.7
@@ -1,1 +0,1 @@ | ||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("@blueprintjs/core"),require("tslib"),require("react"),require("classnames")):"function"==typeof define&&define.amd?define(["@blueprintjs/core","tslib","react","classnames"],t):"object"==typeof exports?exports.Select=t(require("@blueprintjs/core"),require("tslib"),require("react"),require("classnames")):(e.Blueprint=e.Blueprint||{},e.Blueprint.Select=t(e.Blueprint.Core,e.window,e.React,e.classNames))}(window,(function(e,t,n,r){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(r,i,function(t){return e[t]}.bind(null,i));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=12)}([function(t,n){t.exports=e},function(e,n){e.exports=t},function(e,t){e.exports=n},function(e,t,n){"use strict";n.r(t);var r=n(5);n.d(t,"Classes",(function(){return r}));var i=n(6);n.d(t,"renderFilteredItems",(function(){return i.a}));var s=n(7);for(var o in s)["Classes","renderFilteredItems","default"].indexOf(o)<0&&function(e){n.d(t,e,(function(){return s[e]}))}(o);var a=n(8);n.d(t,"executeItemsEqual",(function(){return a.a}));var p=n(9);n.d(t,"getCreateNewItem",(function(){return p.b})),n.d(t,"isCreateNewItem",(function(){return p.c})),n.d(t,"getActiveItem",(function(){return p.a}));var u=n(10);for(var o in u)["Classes","renderFilteredItems","executeItemsEqual","getCreateNewItem","isCreateNewItem","getActiveItem","default"].indexOf(o)<0&&function(e){n.d(t,e,(function(){return u[e]}))}(o)},function(e,t){e.exports=r},function(e,t,n){"use strict";n.r(t),n.d(t,"MULTISELECT",(function(){return s})),n.d(t,"MULTISELECT_POPOVER",(function(){return o})),n.d(t,"MULTISELECT_TAG_INPUT_INPUT",(function(){return a})),n.d(t,"OMNIBAR",(function(){return p})),n.d(t,"OMNIBAR_OVERLAY",(function(){return u})),n.d(t,"SELECT",(function(){return l})),n.d(t,"SELECT_POPOVER",(function(){return c}));var r=n(0),i=r.Classes.getClassNamespace(),s=i+"-multi-select",o=s+"-popover",a=s+"-tag-input-input",p=i+"-omnibar",u=p+"-overlay",l=i+"-select",c=l+"-popover"},function(e,t,n){"use strict";function r(e,t,n){if(0===e.query.length&&void 0!==n)return n;var r=e.filteredItems.map(e.renderItem).filter((function(e){return null!=e}));return r.length>0?r:t}n.d(t,"a",(function(){return r}))},function(e,t){},function(e,t,n){"use strict";n.d(t,"a",(function(){return i}));var r=n(0);function i(e,t,n){return void 0===e||null==t||null==n?t===n:r.Utils.isFunction(e)?e(t,n):t[e]===n[e]}},function(e,t,n){"use strict";function r(){return{__blueprintCreateNewItemBrand:"blueprint-create-new-item"}}function i(e){if(null==e)return!1;var t=Object.keys(e);return 1===t.length&&"__blueprintCreateNewItemBrand"===t[0]&&"blueprint-create-new-item"===e.__blueprintCreateNewItemBrand}function s(e){return null==e||i(e)?null:e}n.d(t,"b",(function(){return r})),n.d(t,"c",(function(){return i})),n.d(t,"a",(function(){return s}))},function(e,t){},function(e,t,n){"use strict";n.d(t,"b",(function(){return y})),n.d(t,"c",(function(){return d})),n.d(t,"f",(function(){return I})),n.d(t,"a",(function(){return O})),n.d(t,"d",(function(){return P})),n.d(t,"e",(function(){return g}));var r=n(1),i=n(4),s=n.n(i),o=n(2),a=n(0),p=n(3),u=n(6),l=n(8),c=n(9),d=function(e){function t(t,n){var r,i=e.call(this,t,n)||this;i.refHandlers={itemsParent:function(e){return i.itemsParentRef=e}},i.shouldCheckActiveItemInViewport=!1,i.expectedNextActiveItem=null,i.isEnterKeyPressed=!1,i.renderItemList=function(e){var t=i.props,n=t.initialContent,r=t.noResults,s=i.isCreateItemRendered()?null:r,p=Object(u.a)(e,s,n),l=i.isCreateItemRendered()?i.renderCreateItemMenuItem(i.state.query.trim()):null;return null==p&&null==l?null:o.createElement(a.Menu,{ulRef:e.itemsParentRef},p,l)},i.renderItem=function(e,t){if(!0!==i.props.disabled){var n=i.state,r=n.activeItem,s=n.query,o=i.state.filteredItems.indexOf(e)>=0,a={active:Object(l.a)(i.props.itemsEqual,Object(c.a)(r),e),disabled:h(e,t,i.props.itemDisabled),matchesPredicate:o};return i.props.itemRenderer(e,{handleClick:function(t){return i.handleItemSelect(e,t)},index:t,modifiers:a,query:s})}return null},i.renderCreateItemMenuItem=function(e){var t=i.state.activeItem,n=Object(c.c)(t);return a.Utils.safeInvoke(i.props.createNewItemRenderer,e,n,(function(t){i.handleItemCreate(e,t)}))},i.handleItemCreate=function(e,t){var n=a.Utils.safeInvoke(i.props.createNewItemFromQuery,e);null!=n&&(a.Utils.safeInvoke(i.props.onItemSelect,n,t),i.maybeResetQuery())},i.handleItemSelect=function(e,t){i.setActiveItem(e),a.Utils.safeInvoke(i.props.onItemSelect,e,t),i.maybeResetQuery()},i.handlePaste=function(e){for(var t,n=i.props,r=n.createNewItemFromQuery,s=n.onItemsPaste,o=[],p=[],u=0,l=e;u<l.length;u++){var c=l[u],d=m(c,i.props);if(void 0!==d)t=d,p.push(d);else if(i.canCreateItems()){var f=a.Utils.safeInvoke(r,c);void 0!==f&&p.push(f)}else o.push(c)}i.setQuery(o.join(", "),!1),void 0!==t&&i.setActiveItem(t),a.Utils.safeInvoke(s,p)},i.handleKeyDown=function(e){var t=e.keyCode;if(t===a.Keys.ARROW_UP||t===a.Keys.ARROW_DOWN){e.preventDefault();var n=i.getNextActiveItem(t===a.Keys.ARROW_UP?-1:1);null!=n&&i.setActiveItem(n)}else t===a.Keys.ENTER&&(i.isEnterKeyPressed=!0);a.Utils.safeInvoke(i.props.onKeyDown,e)},i.handleKeyUp=function(e){var t=i.props.onKeyUp,n=i.state.activeItem;e.keyCode===a.Keys.ENTER&&i.isEnterKeyPressed&&(e.preventDefault(),null==n||Object(c.c)(n)?i.handleItemCreate(i.state.query,e):i.handleItemSelect(n,e),i.isEnterKeyPressed=!1),a.Utils.safeInvoke(t,e)},i.handleInputQueryChange=function(e){var t=null==e?"":e.target.value;i.setQuery(t),a.Utils.safeInvoke(i.props.onQueryChange,t,e)};var s=t.query,p=void 0===s?"":s,d=a.Utils.safeInvoke(t.createNewItemFromQuery,p),f=v(p,t);return i.state={activeItem:void 0!==t.activeItem?t.activeItem:null!==(r=t.initialActiveItem)&&void 0!==r?r:I(f,t.itemDisabled),createNewItem:d,filteredItems:f,query:p},i}return Object(r.__extends)(t,e),t.ofType=function(){return t},t.prototype.render=function(){var e=this.props,t=e.className,n=e.items,i=e.renderer,s=e.itemListRenderer,o=void 0===s?this.renderItemList:s,a=this.state,p=(a.createNewItem,Object(r.__rest)(a,["createNewItem"]));return i(Object(r.__assign)(Object(r.__assign)({},p),{className:t,handleItemSelect:this.handleItemSelect,handleKeyDown:this.handleKeyDown,handleKeyUp:this.handleKeyUp,handlePaste:this.handlePaste,handleQueryChange:this.handleInputQueryChange,itemList:o(Object(r.__assign)(Object(r.__assign)({},p),{items:n,itemsParentRef:this.refHandlers.itemsParent,renderItem:this.renderItem}))}))},t.prototype.componentDidUpdate=function(e){var t=this;void 0!==this.props.activeItem&&this.props.activeItem!==this.state.activeItem&&(this.shouldCheckActiveItemInViewport=!0,this.setState({activeItem:this.props.activeItem})),null!=this.props.query&&this.props.query!==e.query?this.setQuery(this.props.query,this.props.resetOnQuery,this.props):a.Utils.shallowCompareKeys(this.props,e,{include:["items","itemListPredicate","itemPredicate"]})||this.setQuery(this.state.query),this.shouldCheckActiveItemInViewport&&(requestAnimationFrame((function(){return t.scrollActiveItemIntoView()})),this.shouldCheckActiveItemInViewport=!1)},t.prototype.scrollActiveItemIntoView=function(){var e=!1!==this.props.scrollToActiveItem,t=!Object(l.a)(this.props.itemsEqual,Object(c.a)(this.expectedNextActiveItem),Object(c.a)(this.props.activeItem));if(this.expectedNextActiveItem=null,e||!t){var n=this.getActiveElement();if(null!=this.itemsParentRef&&null!=n){var r=n.offsetTop,i=n.offsetHeight,s=this.itemsParentRef,o=s.offsetTop,a=s.scrollTop,p=s.clientHeight,u=this.getItemsParentPadding(),d=u.paddingTop,f=r+i+u.paddingBottom-o,m=r-d-o;f>=a+p?this.itemsParentRef.scrollTop=f+i-p:m<=a&&(this.itemsParentRef.scrollTop=m-i)}}},t.prototype.setQuery=function(e,t,n){void 0===t&&(t=this.props.resetOnQuery),void 0===n&&(n=this.props);var r=n.createNewItemFromQuery;this.shouldCheckActiveItemInViewport=!0,e!==this.state.query&&a.Utils.safeInvoke(n.onQueryChange,e);var i=e.trim(),s=v(i,n),o=null!=r&&""!==i?r(i):void 0;this.setState({createNewItem:o,filteredItems:s,query:e});var p=this.getActiveIndex(s);(t||p<0||h(Object(c.a)(this.state.activeItem),p,n.itemDisabled))&&this.setActiveItem(I(s,n.itemDisabled))},t.prototype.setActiveItem=function(e){this.expectedNextActiveItem=e,void 0===this.props.activeItem&&(this.shouldCheckActiveItemInViewport=!0,this.setState({activeItem:e})),Object(c.c)(e)?a.Utils.safeInvoke(this.props.onActiveItemChange,null,!0):a.Utils.safeInvoke(this.props.onActiveItemChange,e,!1)},t.prototype.getActiveElement=function(){var e=this.state.activeItem;if(null!=this.itemsParentRef){if(Object(c.c)(e))return this.itemsParentRef.children.item(this.state.filteredItems.length);var t=this.getActiveIndex();return this.itemsParentRef.children.item(t)}},t.prototype.getActiveIndex=function(e){void 0===e&&(e=this.state.filteredItems);var t=this.state.activeItem;if(null==t||Object(c.c)(t))return-1;for(var n=0;n<e.length;++n)if(Object(l.a)(this.props.itemsEqual,e[n],t))return n;return-1},t.prototype.getItemsParentPadding=function(){var e=getComputedStyle(this.itemsParentRef),t=e.paddingTop;return{paddingBottom:f(e.paddingBottom),paddingTop:f(t)}},t.prototype.getNextActiveItem=function(e,t){if((void 0===t&&(t=this.getActiveIndex()),this.isCreateItemRendered())&&(0===t&&-1===e||t===this.state.filteredItems.length-1&&1===e))return Object(c.b)();return I(this.state.filteredItems,this.props.itemDisabled,e,t)},t.prototype.isCreateItemRendered=function(){return this.canCreateItems()&&""!==this.state.query&&!this.wouldCreatedItemMatchSomeExistingItem()},t.prototype.canCreateItems=function(){return null!=this.props.createNewItemFromQuery&&null!=this.props.createNewItemRenderer},t.prototype.wouldCreatedItemMatchSomeExistingItem=function(){var e=this;return this.state.filteredItems.some((function(t){return Object(l.a)(e.props.itemsEqual,t,e.state.createNewItem)}))},t.prototype.maybeResetQuery=function(){this.props.resetOnSelect&&this.setQuery("",!0)},t.displayName=a.DISPLAYNAME_PREFIX+".QueryList",t.defaultProps={disabled:!1,resetOnQuery:!0},t}(a.AbstractComponent2);function f(e){return null==e?0:parseInt(e.slice(0,-2),10)}function m(e,t){var n=t.items,r=t.itemPredicate;if(a.Utils.isFunction(r))for(var i=0;i<n.length;i++){var s=n[i];if(r(e,s,i,!0))return s}}function v(e,t){var n=t.items,r=t.itemPredicate,i=t.itemListPredicate;return a.Utils.isFunction(i)?i(e,n):a.Utils.isFunction(r)?n.filter((function(t,n){return r(e,t,n)})):n}function h(e,t,n){return null!=n&&null!=e&&(a.Utils.isFunction(n)?n(e,t):!!e[n])}function I(e,t,n,r){if(void 0===n&&(n=1),void 0===r&&(r=e.length-1),0===e.length)return null;var i,s,o,a=r,p=e.length-1;do{if(o=p,!h(e[a=(i=a+n)<(s=0)?o:i>o?s:i],a,t))return e[a]}while(a!==r&&-1!==r);return null}var y=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.TypedQueryList=d.ofType(),t.renderQueryList=function(e){var n=t.props,i=n.inputProps,u=void 0===i?{}:i,l=n.isOpen,c=n.overlayProps,d=void 0===c?{}:c,f=e.handleKeyDown,m=e.handleKeyUp,v=l?{onKeyDown:f,onKeyUp:m}:{};return o.createElement(a.Overlay,Object(r.__assign)({hasBackdrop:!0},d,{isOpen:l,className:s()(p.Classes.OMNIBAR_OVERLAY,d.className),onClose:t.handleOverlayClose}),o.createElement("div",Object(r.__assign)({className:s()(p.Classes.OMNIBAR,e.className)},v),o.createElement(a.InputGroup,Object(r.__assign)({autoFocus:!0,large:!0,leftIcon:"search",placeholder:"Search..."},u,{onChange:e.handleQueryChange,value:e.query})),e.itemList))},t.handleOverlayClose=function(e){a.Utils.safeInvokeMember(t.props.overlayProps,"onClose",e),a.Utils.safeInvoke(t.props.onClose,e)},t}return Object(r.__extends)(t,e),t.ofType=function(){return t},t.prototype.render=function(){var e=this.props,t=e.initialContent,n=void 0===t?null:t,i=(e.isOpen,e.inputProps,e.overlayProps,Object(r.__rest)(e,["initialContent","isOpen","inputProps","overlayProps"]));return o.createElement(this.TypedQueryList,Object(r.__assign)({},i,{initialContent:n,renderer:this.renderQueryList}))},t.displayName=a.DISPLAYNAME_PREFIX+".Omnibar",t}(o.PureComponent),O=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.state={isOpen:t.props.popoverProps&&t.props.popoverProps.isOpen||!1},t.TypedQueryList=d.ofType(),t.input=null,t.queryList=null,t.refHandlers={input:function(e){t.input=e,a.Utils.safeInvokeMember(t.props.tagInputProps,"inputRef",e)},queryList:function(e){return t.queryList=e}},t.renderQueryList=function(e){var n,i=t.props,u=i.fill,l=i.tagInputProps,c=void 0===l?{}:l,d=i.popoverProps,f=void 0===d?{}:d,m=i.selectedItems,v=void 0===m?[]:m,h=i.placeholder,I=e.handlePaste,y=e.handleKeyDown,O=e.handleKeyUp;u&&(f.fill=!0,c.fill=!0);var P=Object(r.__assign)(Object(r.__assign)({},c.inputProps),{className:s()(null===(n=c.inputProps)||void 0===n?void 0:n.className,p.Classes.MULTISELECT_TAG_INPUT_INPUT)});return o.createElement(a.Popover,Object(r.__assign)({autoFocus:!1,canEscapeKeyClose:!0,enforceFocus:!1,isOpen:t.state.isOpen,position:a.Position.BOTTOM_LEFT},f,{className:s()(e.className,f.className),interactionKind:a.PopoverInteractionKind.CLICK,onInteraction:t.handlePopoverInteraction,popoverClassName:s()(p.Classes.MULTISELECT_POPOVER,f.popoverClassName),onOpened:t.handlePopoverOpened}),o.createElement("div",{onKeyDown:t.getTagInputKeyDownHandler(y),onKeyUp:t.getTagInputKeyUpHandler(O)},o.createElement(a.TagInput,Object(r.__assign)({placeholder:h},c,{className:s()(p.Classes.MULTISELECT,c.className),inputRef:t.refHandlers.input,inputProps:P,inputValue:e.query,onAdd:function(e,t){"paste"===t&&I(e)},onInputChange:e.handleQueryChange,values:v.map(t.props.tagRenderer)}))),o.createElement("div",{onKeyDown:y,onKeyUp:O},e.itemList))},t.handleItemSelect=function(e,n){null!=t.input&&t.input.focus(),a.Utils.safeInvoke(t.props.onItemSelect,e,n)},t.handleQueryChange=function(e,n){t.setState({isOpen:e.length>0||!t.props.openOnKeyDown}),a.Utils.safeInvoke(t.props.onQueryChange,e,n)},t.handlePopoverInteraction=function(e){return requestAnimationFrame((function(){var n,r,i=t.input===document.activeElement;null==t.input||i?t.props.openOnKeyDown||t.setState({isOpen:!0}):t.setState({isOpen:!1}),null===(r=null===(n=t.props.popoverProps)||void 0===n?void 0:n.onInteraction)||void 0===r||r.call(n,e)}))},t.handlePopoverOpened=function(e){null!=t.queryList&&t.queryList.scrollActiveItemIntoView(),a.Utils.safeInvokeMember(t.props.popoverProps,"onOpened",e)},t.getTagInputKeyDownHandler=function(e){return function(n){var r=n.which;r===a.Keys.ESCAPE||r===a.Keys.TAB?(null!=t.input&&t.input.blur(),t.setState({isOpen:!1})):r!==a.Keys.BACKSPACE&&r!==a.Keys.ARROW_LEFT&&r!==a.Keys.ARROW_RIGHT&&t.setState({isOpen:!0});var i=null!=n.target.closest("."+a.Classes.TAG_REMOVE);t.state.isOpen&&!i&&a.Utils.safeInvoke(e,n)}},t.getTagInputKeyUpHandler=function(e){return function(n){var r=n.target.classList.contains(p.Classes.MULTISELECT_TAG_INPUT_INPUT);t.state.isOpen&&r&&a.Utils.safeInvoke(e,n)}},t}return Object(r.__extends)(t,e),t.ofType=function(){return t},t.prototype.render=function(){var e=this.props,t=(e.openOnKeyDown,e.popoverProps,e.tagInputProps,Object(r.__rest)(e,["openOnKeyDown","popoverProps","tagInputProps"]));return o.createElement(this.TypedQueryList,Object(r.__assign)({},t,{onItemSelect:this.handleItemSelect,onQueryChange:this.handleQueryChange,ref:this.refHandlers.queryList,renderer:this.renderQueryList}))},t.displayName=a.DISPLAYNAME_PREFIX+".MultiSelect",t.defaultProps={fill:!1,placeholder:"Search..."},t}(o.PureComponent),P=function(e){function t(){var t,n=e.apply(this,arguments)||this;return n.state={isOpen:!1},n.TypedQueryList=d.ofType(),n.inputEl=null,n.queryList=null,n.refHandlers={input:Object(a.isRefObject)(null===(t=n.props.inputProps)||void 0===t?void 0:t.inputRef)?n.inputEl=n.props.inputProps.inputRef:function(e){var t,r;n.inputEl=e,null===(r=null===(t=n.props.inputProps)||void 0===t?void 0:t.inputRef)||void 0===r||r(e)},queryList:function(e){return n.queryList=e}},n.renderQueryList=function(e){var t=n.props,i=t.filterable,u=void 0===i||i,l=t.disabled,c=void 0!==l&&l,d=t.inputProps,f=void 0===d?{}:d,m=t.popoverProps,v=void 0===m?{}:m,h=o.createElement(a.InputGroup,Object(r.__assign)({leftIcon:"search",placeholder:"Filter...",rightElement:n.maybeRenderClearButton(e.query)},f,{inputRef:n.refHandlers.input,onChange:e.handleQueryChange,value:e.query})),I=e.handleKeyDown,y=e.handleKeyUp;return o.createElement(a.Popover,Object(r.__assign)({autoFocus:!1,enforceFocus:!1,isOpen:n.state.isOpen,disabled:c,position:a.Position.BOTTOM_LEFT},v,{className:s()(e.className,v.className),onInteraction:n.handlePopoverInteraction,popoverClassName:s()(p.Classes.SELECT_POPOVER,v.popoverClassName),onOpening:n.handlePopoverOpening,onOpened:n.handlePopoverOpened,onClosing:n.handlePopoverClosing}),o.createElement("div",{onKeyDown:n.state.isOpen?I:n.handleTargetKeyDown,onKeyUp:n.state.isOpen?y:void 0},n.props.children),o.createElement("div",{onKeyDown:I,onKeyUp:y},u?h:void 0,e.itemList))},n.handleTargetKeyDown=function(e){e.which!==a.Keys.ARROW_UP&&e.which!==a.Keys.ARROW_DOWN||(e.preventDefault(),n.setState({isOpen:!0}))},n.handleItemSelect=function(e,t){n.setState({isOpen:!1}),a.Utils.safeInvoke(n.props.onItemSelect,e,t)},n.handlePopoverInteraction=function(e){n.setState({isOpen:e}),a.Utils.safeInvokeMember(n.props.popoverProps,"onInteraction",e)},n.handlePopoverOpening=function(e){n.previousFocusedElement=document.activeElement,n.props.resetOnClose&&n.resetQuery(),a.Utils.safeInvokeMember(n.props.popoverProps,"onOpening",e)},n.handlePopoverOpened=function(e){null!=n.queryList&&n.queryList.scrollActiveItemIntoView(),requestAnimationFrame((function(){var e=n.props.inputProps;!1!==(void 0===e?{}:e).autoFocus&&null!=n.inputEl&&Object(a.getRef)(n.inputEl).focus()})),a.Utils.safeInvokeMember(n.props.popoverProps,"onOpened",e)},n.handlePopoverClosing=function(e){requestAnimationFrame((function(){void 0!==n.previousFocusedElement&&(n.previousFocusedElement.focus(),n.previousFocusedElement=void 0)})),a.Utils.safeInvokeMember(n.props.popoverProps,"onClosing",e)},n.resetQuery=function(){return n.queryList&&n.queryList.setQuery("",!0)},n}return Object(r.__extends)(t,e),t.ofType=function(){return t},t.prototype.render=function(){var e=this.props,t=(e.filterable,e.inputProps,e.popoverProps,Object(r.__rest)(e,["filterable","inputProps","popoverProps"]));return o.createElement(this.TypedQueryList,Object(r.__assign)({},t,{onItemSelect:this.handleItemSelect,ref:this.refHandlers.queryList,renderer:this.renderQueryList}))},t.prototype.componentDidUpdate=function(e,t){this.state.isOpen&&!t.isOpen&&null!=this.queryList&&this.queryList.scrollActiveItemIntoView()},t.prototype.maybeRenderClearButton=function(e){return e.length>0?o.createElement(a.Button,{icon:"cross",minimal:!0,onClick:this.resetQuery}):void 0},t.displayName=a.DISPLAYNAME_PREFIX+".Select",t}(o.PureComponent),g=function(e){function t(){var t,n=e.apply(this,arguments)||this;return n.state={isOpen:null!=n.props.popoverProps&&n.props.popoverProps.isOpen||!1,selectedItem:n.getInitialSelectedItem()},n.TypedQueryList=d.ofType(),n.inputEl=null,n.queryList=null,n.refHandlers={input:Object(a.isRefObject)(null===(t=n.props.inputProps)||void 0===t?void 0:t.inputRef)?n.inputEl=n.props.inputProps.inputRef:function(e){var t,r;n.inputEl=e,null===(r=null===(t=n.props.inputProps)||void 0===t?void 0:t.inputRef)||void 0===r||r(e)},queryList:function(e){return n.queryList=e}},n.renderQueryList=function(e){var t=n.props,i=t.fill,u=t.inputProps,l=void 0===u?{}:u,c=t.popoverProps,d=void 0===c?{}:c,f=n.state,m=f.isOpen,v=f.selectedItem,h=e.handleKeyDown,I=e.handleKeyUp,y=l.autoComplete,O=void 0===y?"off":y,P=l.placeholder,g=void 0===P?"Search...":P,b=v?n.props.inputValueRenderer(v):"",C=m&&b?b:g,E=m?e.query:b||(n.props.resetOnClose?"":e.query);return i&&(d.fill=!0,l.fill=!0),o.createElement(a.Popover,Object(r.__assign)({autoFocus:!1,enforceFocus:!1,isOpen:m,position:a.Position.BOTTOM_LEFT},d,{className:s()(e.className,d.className),interactionKind:a.PopoverInteractionKind.CLICK,onInteraction:n.handlePopoverInteraction,popoverClassName:s()(p.Classes.SELECT_POPOVER,d.popoverClassName),onOpening:n.handlePopoverOpening,onOpened:n.handlePopoverOpened}),o.createElement(a.InputGroup,Object(r.__assign)({autoComplete:O,disabled:n.props.disabled},l,{inputRef:n.refHandlers.input,onChange:e.handleQueryChange,onFocus:n.handleInputFocus,onKeyDown:n.getTargetKeyDownHandler(h),onKeyUp:n.getTargetKeyUpHandler(I),placeholder:C,value:E})),o.createElement("div",{onKeyDown:h,onKeyUp:I},e.itemList))},n.selectText=function(){requestAnimationFrame((function(){if(null!=n.inputEl){var e=Object(a.getRef)(n.inputEl);e.setSelectionRange(0,e.value.length)}}))},n.handleInputFocus=function(e){n.selectText(),n.props.openOnKeyDown||n.setState({isOpen:!0}),a.Utils.safeInvokeMember(n.props.inputProps,"onFocus",e)},n.handleItemSelect=function(e,t){var r;n.props.closeOnSelect?(null!=n.inputEl&&Object(a.getRef)(n.inputEl).blur(),r=!1):(null!=n.inputEl&&Object(a.getRef)(n.inputEl).focus(),n.selectText(),r=!0),void 0===n.props.selectedItem?n.setState({isOpen:r,selectedItem:e}):n.setState({isOpen:r}),a.Utils.safeInvoke(n.props.onItemSelect,e,t)},n.handlePopoverInteraction=function(e){return requestAnimationFrame((function(){var t=Object(a.getRef)(n.inputEl)===document.activeElement;null==n.inputEl||t||n.setState({isOpen:!1}),a.Utils.safeInvokeMember(n.props.popoverProps,"onInteraction",e)}))},n.handlePopoverOpening=function(e){n.props.resetOnClose&&n.queryList&&n.queryList.setQuery("",!0),a.Utils.safeInvokeMember(n.props.popoverProps,"onOpening",e)},n.handlePopoverOpened=function(e){null!=n.queryList&&n.queryList.scrollActiveItemIntoView(),a.Utils.safeInvokeMember(n.props.popoverProps,"onOpened",e)},n.getTargetKeyDownHandler=function(e){return function(t){var r=t.which;r===a.Keys.ESCAPE||r===a.Keys.TAB?(null!=n.inputEl&&Object(a.getRef)(n.inputEl).blur(),n.setState({isOpen:!1})):n.props.openOnKeyDown&&r!==a.Keys.BACKSPACE&&r!==a.Keys.ARROW_LEFT&&r!==a.Keys.ARROW_RIGHT&&n.setState({isOpen:!0}),n.state.isOpen&&a.Utils.safeInvoke(e,t),a.Utils.safeInvokeMember(n.props.inputProps,"onKeyDown",t)}},n.getTargetKeyUpHandler=function(e){return function(t){n.state.isOpen&&a.Utils.safeInvoke(e,t),a.Utils.safeInvokeMember(n.props.inputProps,"onKeyUp",t)}},n}return Object(r.__extends)(t,e),t.ofType=function(){return t},t.prototype.render=function(){var e,t=this.props,n=(t.disabled,t.inputProps,t.popoverProps,Object(r.__rest)(t,["disabled","inputProps","popoverProps"]));return o.createElement(this.TypedQueryList,Object(r.__assign)({},n,{initialActiveItem:null!==(e=this.props.selectedItem)&&void 0!==e?e:void 0,onItemSelect:this.handleItemSelect,ref:this.refHandlers.queryList,renderer:this.renderQueryList}))},t.prototype.componentDidUpdate=function(e,t){var n,r,i=this;void 0!==this.props.selectedItem&&this.props.selectedItem!==this.state.selectedItem&&this.setState({selectedItem:this.props.selectedItem}),!1===this.state.isOpen&&!0===t.isOpen&&setTimeout((function(){i.maybeResetActiveItemToSelectedItem()}),null!==(r=null===(n=this.props.popoverProps)||void 0===n?void 0:n.transitionDuration)&&void 0!==r?r:a.Popover.defaultProps.transitionDuration),this.state.isOpen&&!t.isOpen&&null!=this.queryList&&this.queryList.scrollActiveItemIntoView()},t.prototype.getInitialSelectedItem=function(){return void 0!==this.props.selectedItem?this.props.selectedItem:void 0!==this.props.defaultSelectedItem?this.props.defaultSelectedItem:null},t.prototype.maybeResetActiveItemToSelectedItem=function(){var e,t=void 0===this.props.activeItem&&null!==this.state.selectedItem&&!this.props.resetOnSelect;null!==this.queryList&&t&&this.queryList.setActiveItem(null!==(e=this.props.selectedItem)&&void 0!==e?e:this.state.selectedItem)},t.displayName=a.DISPLAYNAME_PREFIX+".Suggest",t.defaultProps={closeOnSelect:!0,fill:!1,openOnKeyDown:!1,resetOnClose:!1},t}(o.PureComponent)},function(e,t,n){e.exports=n(13)},function(e,t,n){"use strict";n.r(t);var r=n(3);for(var i in r)"default"!==i&&function(e){n.d(t,e,(function(){return r[e]}))}(i);var s=n(11);n.d(t,"Omnibar",(function(){return s.b})),n.d(t,"QueryList",(function(){return s.c})),n.d(t,"getFirstEnabledItem",(function(){return s.f})),n.d(t,"MultiSelect",(function(){return s.a})),n.d(t,"Select",(function(){return s.d})),n.d(t,"Suggest",(function(){return s.e}))}])})); | ||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("@blueprintjs/core"),require("tslib"),require("react"),require("classnames")):"function"==typeof define&&define.amd?define(["@blueprintjs/core","tslib","react","classnames"],t):"object"==typeof exports?exports.Select=t(require("@blueprintjs/core"),require("tslib"),require("react"),require("classnames")):(e.Blueprint=e.Blueprint||{},e.Blueprint.Select=t(e.Blueprint.Core,e.window,e.React,e.classNames))}(window,(function(e,t,n,r){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(r,i,function(t){return e[t]}.bind(null,i));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=12)}([function(t,n){t.exports=e},function(e,n){e.exports=t},function(e,t){e.exports=n},function(e,t,n){"use strict";n.r(t);var r=n(5);n.d(t,"Classes",(function(){return r}));var i=n(6);n.d(t,"renderFilteredItems",(function(){return i.a}));var s=n(7);for(var o in s)["default","Classes","renderFilteredItems"].indexOf(o)<0&&function(e){n.d(t,e,(function(){return s[e]}))}(o);var a=n(8);n.d(t,"executeItemsEqual",(function(){return a.a}));var p=n(9);n.d(t,"getCreateNewItem",(function(){return p.b})),n.d(t,"isCreateNewItem",(function(){return p.c})),n.d(t,"getActiveItem",(function(){return p.a}));var u=n(10);for(var o in u)["default","Classes","renderFilteredItems","executeItemsEqual","getCreateNewItem","isCreateNewItem","getActiveItem"].indexOf(o)<0&&function(e){n.d(t,e,(function(){return u[e]}))}(o)},function(e,t){e.exports=r},function(e,t,n){"use strict";n.r(t),n.d(t,"MULTISELECT",(function(){return s})),n.d(t,"MULTISELECT_POPOVER",(function(){return o})),n.d(t,"MULTISELECT_TAG_INPUT_INPUT",(function(){return a})),n.d(t,"OMNIBAR",(function(){return p})),n.d(t,"OMNIBAR_OVERLAY",(function(){return u})),n.d(t,"SELECT",(function(){return l})),n.d(t,"SELECT_POPOVER",(function(){return c}));var r=n(0),i=r.Classes.getClassNamespace(),s=i+"-multi-select",o=s+"-popover",a=s+"-tag-input-input",p=i+"-omnibar",u=p+"-overlay",l=i+"-select",c=l+"-popover"},function(e,t,n){"use strict";function r(e,t,n){if(0===e.query.length&&void 0!==n)return n;var r=e.filteredItems.map(e.renderItem).filter((function(e){return null!=e}));return r.length>0?r:t}n.d(t,"a",(function(){return r}))},function(e,t){},function(e,t,n){"use strict";n.d(t,"a",(function(){return i}));var r=n(0);function i(e,t,n){return void 0===e||null==t||null==n?t===n:r.Utils.isFunction(e)?e(t,n):t[e]===n[e]}},function(e,t,n){"use strict";function r(){return{__blueprintCreateNewItemBrand:"blueprint-create-new-item"}}function i(e){if(null==e)return!1;var t=Object.keys(e);return 1===t.length&&"__blueprintCreateNewItemBrand"===t[0]&&"blueprint-create-new-item"===e.__blueprintCreateNewItemBrand}function s(e){return null==e||i(e)?null:e}n.d(t,"b",(function(){return r})),n.d(t,"c",(function(){return i})),n.d(t,"a",(function(){return s}))},function(e,t){},function(e,t,n){"use strict";n.d(t,"b",(function(){return y})),n.d(t,"c",(function(){return d})),n.d(t,"f",(function(){return I})),n.d(t,"a",(function(){return O})),n.d(t,"d",(function(){return P})),n.d(t,"e",(function(){return g}));var r=n(1),i=n(4),s=n.n(i),o=n(2),a=n(0),p=n(3),u=n(6),l=n(8),c=n(9),d=function(e){function t(t,n){var r,i=e.call(this,t,n)||this;i.refHandlers={itemsParent:function(e){return i.itemsParentRef=e}},i.shouldCheckActiveItemInViewport=!1,i.expectedNextActiveItem=null,i.isEnterKeyPressed=!1,i.renderItemList=function(e){var t=i.props,n=t.initialContent,r=t.noResults,s=i.isCreateItemRendered()?null:r,p=Object(u.a)(e,s,n),l=i.isCreateItemRendered()?i.renderCreateItemMenuItem(i.state.query.trim()):null;return null==p&&null==l?null:o.createElement(a.Menu,{ulRef:e.itemsParentRef},p,l)},i.renderItem=function(e,t){if(!0!==i.props.disabled){var n=i.state,r=n.activeItem,s=n.query,o=i.state.filteredItems.indexOf(e)>=0,a={active:Object(l.a)(i.props.itemsEqual,Object(c.a)(r),e),disabled:h(e,t,i.props.itemDisabled),matchesPredicate:o};return i.props.itemRenderer(e,{handleClick:function(t){return i.handleItemSelect(e,t)},index:t,modifiers:a,query:s})}return null},i.renderCreateItemMenuItem=function(e){var t=i.state.activeItem,n=Object(c.c)(t);return a.Utils.safeInvoke(i.props.createNewItemRenderer,e,n,(function(t){i.handleItemCreate(e,t)}))},i.handleItemCreate=function(e,t){var n=a.Utils.safeInvoke(i.props.createNewItemFromQuery,e);null!=n&&(a.Utils.safeInvoke(i.props.onItemSelect,n,t),i.maybeResetQuery())},i.handleItemSelect=function(e,t){i.setActiveItem(e),a.Utils.safeInvoke(i.props.onItemSelect,e,t),i.maybeResetQuery()},i.handlePaste=function(e){for(var t,n=i.props,r=n.createNewItemFromQuery,s=n.onItemsPaste,o=[],p=[],u=0,l=e;u<l.length;u++){var c=l[u],d=m(c,i.props);if(void 0!==d)t=d,p.push(d);else if(i.canCreateItems()){var f=a.Utils.safeInvoke(r,c);void 0!==f&&p.push(f)}else o.push(c)}i.setQuery(o.join(", "),!1),void 0!==t&&i.setActiveItem(t),a.Utils.safeInvoke(s,p)},i.handleKeyDown=function(e){var t=e.keyCode;if(t===a.Keys.ARROW_UP||t===a.Keys.ARROW_DOWN){e.preventDefault();var n=i.getNextActiveItem(t===a.Keys.ARROW_UP?-1:1);null!=n&&i.setActiveItem(n)}else t===a.Keys.ENTER&&(i.isEnterKeyPressed=!0);a.Utils.safeInvoke(i.props.onKeyDown,e)},i.handleKeyUp=function(e){var t=i.props.onKeyUp,n=i.state.activeItem;e.keyCode===a.Keys.ENTER&&i.isEnterKeyPressed&&(e.preventDefault(),null==n||Object(c.c)(n)?i.handleItemCreate(i.state.query,e):i.handleItemSelect(n,e),i.isEnterKeyPressed=!1),a.Utils.safeInvoke(t,e)},i.handleInputQueryChange=function(e){var t=null==e?"":e.target.value;i.setQuery(t),a.Utils.safeInvoke(i.props.onQueryChange,t,e)};var s=t.query,p=void 0===s?"":s,d=a.Utils.safeInvoke(t.createNewItemFromQuery,p),f=v(p,t);return i.state={activeItem:void 0!==t.activeItem?t.activeItem:null!==(r=t.initialActiveItem)&&void 0!==r?r:I(f,t.itemDisabled),createNewItem:d,filteredItems:f,query:p},i}return Object(r.__extends)(t,e),t.ofType=function(){return t},t.prototype.render=function(){var e=this.props,t=e.className,n=e.items,i=e.renderer,s=e.itemListRenderer,o=void 0===s?this.renderItemList:s,a=this.state,p=(a.createNewItem,Object(r.__rest)(a,["createNewItem"]));return i(Object(r.__assign)(Object(r.__assign)({},p),{className:t,handleItemSelect:this.handleItemSelect,handleKeyDown:this.handleKeyDown,handleKeyUp:this.handleKeyUp,handlePaste:this.handlePaste,handleQueryChange:this.handleInputQueryChange,itemList:o(Object(r.__assign)(Object(r.__assign)({},p),{items:n,itemsParentRef:this.refHandlers.itemsParent,renderItem:this.renderItem}))}))},t.prototype.componentDidUpdate=function(e){var t=this;void 0!==this.props.activeItem&&this.props.activeItem!==this.state.activeItem&&(this.shouldCheckActiveItemInViewport=!0,this.setState({activeItem:this.props.activeItem})),null!=this.props.query&&this.props.query!==e.query?this.setQuery(this.props.query,this.props.resetOnQuery,this.props):a.Utils.shallowCompareKeys(this.props,e,{include:["items","itemListPredicate","itemPredicate"]})||this.setQuery(this.state.query),this.shouldCheckActiveItemInViewport&&(requestAnimationFrame((function(){return t.scrollActiveItemIntoView()})),this.shouldCheckActiveItemInViewport=!1)},t.prototype.scrollActiveItemIntoView=function(){var e=!1!==this.props.scrollToActiveItem,t=!Object(l.a)(this.props.itemsEqual,Object(c.a)(this.expectedNextActiveItem),Object(c.a)(this.props.activeItem));if(this.expectedNextActiveItem=null,e||!t){var n=this.getActiveElement();if(null!=this.itemsParentRef&&null!=n){var r=n.offsetTop,i=n.offsetHeight,s=this.itemsParentRef,o=s.offsetTop,a=s.scrollTop,p=s.clientHeight,u=this.getItemsParentPadding(),d=u.paddingTop,f=r+i+u.paddingBottom-o,m=r-d-o;f>=a+p?this.itemsParentRef.scrollTop=f+i-p:m<=a&&(this.itemsParentRef.scrollTop=m-i)}}},t.prototype.setQuery=function(e,t,n){void 0===t&&(t=this.props.resetOnQuery),void 0===n&&(n=this.props);var r=n.createNewItemFromQuery;this.shouldCheckActiveItemInViewport=!0,e!==this.state.query&&a.Utils.safeInvoke(n.onQueryChange,e);var i=e.trim(),s=v(i,n),o=null!=r&&""!==i?r(i):void 0;this.setState({createNewItem:o,filteredItems:s,query:e});var p=this.getActiveIndex(s);(t||p<0||h(Object(c.a)(this.state.activeItem),p,n.itemDisabled))&&this.setActiveItem(I(s,n.itemDisabled))},t.prototype.setActiveItem=function(e){this.expectedNextActiveItem=e,void 0===this.props.activeItem&&(this.shouldCheckActiveItemInViewport=!0,this.setState({activeItem:e})),Object(c.c)(e)?a.Utils.safeInvoke(this.props.onActiveItemChange,null,!0):a.Utils.safeInvoke(this.props.onActiveItemChange,e,!1)},t.prototype.getActiveElement=function(){var e=this.state.activeItem;if(null!=this.itemsParentRef){if(Object(c.c)(e))return this.itemsParentRef.children.item(this.state.filteredItems.length);var t=this.getActiveIndex();return this.itemsParentRef.children.item(t)}},t.prototype.getActiveIndex=function(e){void 0===e&&(e=this.state.filteredItems);var t=this.state.activeItem;if(null==t||Object(c.c)(t))return-1;for(var n=0;n<e.length;++n)if(Object(l.a)(this.props.itemsEqual,e[n],t))return n;return-1},t.prototype.getItemsParentPadding=function(){var e=getComputedStyle(this.itemsParentRef),t=e.paddingTop;return{paddingBottom:f(e.paddingBottom),paddingTop:f(t)}},t.prototype.getNextActiveItem=function(e,t){if((void 0===t&&(t=this.getActiveIndex()),this.isCreateItemRendered())&&(0===t&&-1===e||t===this.state.filteredItems.length-1&&1===e))return Object(c.b)();return I(this.state.filteredItems,this.props.itemDisabled,e,t)},t.prototype.isCreateItemRendered=function(){return this.canCreateItems()&&""!==this.state.query&&!this.wouldCreatedItemMatchSomeExistingItem()},t.prototype.canCreateItems=function(){return null!=this.props.createNewItemFromQuery&&null!=this.props.createNewItemRenderer},t.prototype.wouldCreatedItemMatchSomeExistingItem=function(){var e=this;return this.state.filteredItems.some((function(t){return Object(l.a)(e.props.itemsEqual,t,e.state.createNewItem)}))},t.prototype.maybeResetQuery=function(){this.props.resetOnSelect&&this.setQuery("",!0)},t.displayName=a.DISPLAYNAME_PREFIX+".QueryList",t.defaultProps={disabled:!1,resetOnQuery:!0},t}(a.AbstractComponent2);function f(e){return null==e?0:parseInt(e.slice(0,-2),10)}function m(e,t){var n=t.items,r=t.itemPredicate;if(a.Utils.isFunction(r))for(var i=0;i<n.length;i++){var s=n[i];if(r(e,s,i,!0))return s}}function v(e,t){var n=t.items,r=t.itemPredicate,i=t.itemListPredicate;return a.Utils.isFunction(i)?i(e,n):a.Utils.isFunction(r)?n.filter((function(t,n){return r(e,t,n)})):n}function h(e,t,n){return null!=n&&null!=e&&(a.Utils.isFunction(n)?n(e,t):!!e[n])}function I(e,t,n,r){if(void 0===n&&(n=1),void 0===r&&(r=e.length-1),0===e.length)return null;var i,s,o,a=r,p=e.length-1;do{if(o=p,!h(e[a=(i=a+n)<(s=0)?o:i>o?s:i],a,t))return e[a]}while(a!==r&&-1!==r);return null}var y=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.TypedQueryList=d.ofType(),t.renderQueryList=function(e){var n=t.props,i=n.inputProps,u=void 0===i?{}:i,l=n.isOpen,c=n.overlayProps,d=void 0===c?{}:c,f=e.handleKeyDown,m=e.handleKeyUp,v=l?{onKeyDown:f,onKeyUp:m}:{};return o.createElement(a.Overlay,Object(r.__assign)({hasBackdrop:!0},d,{isOpen:l,className:s()(p.Classes.OMNIBAR_OVERLAY,d.className),onClose:t.handleOverlayClose}),o.createElement("div",Object(r.__assign)({className:s()(p.Classes.OMNIBAR,e.className)},v),o.createElement(a.InputGroup,Object(r.__assign)({autoFocus:!0,large:!0,leftIcon:"search",placeholder:"Search..."},u,{onChange:e.handleQueryChange,value:e.query})),e.itemList))},t.handleOverlayClose=function(e){a.Utils.safeInvokeMember(t.props.overlayProps,"onClose",e),a.Utils.safeInvoke(t.props.onClose,e)},t}return Object(r.__extends)(t,e),t.ofType=function(){return t},t.prototype.render=function(){var e=this.props,t=e.initialContent,n=void 0===t?null:t,i=(e.isOpen,e.inputProps,e.overlayProps,Object(r.__rest)(e,["initialContent","isOpen","inputProps","overlayProps"]));return o.createElement(this.TypedQueryList,Object(r.__assign)({},i,{initialContent:n,renderer:this.renderQueryList}))},t.displayName=a.DISPLAYNAME_PREFIX+".Omnibar",t}(o.PureComponent),O=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.state={isOpen:t.props.popoverProps&&t.props.popoverProps.isOpen||!1},t.TypedQueryList=d.ofType(),t.input=null,t.queryList=null,t.refHandlers={input:function(e){t.input=e,a.Utils.safeInvokeMember(t.props.tagInputProps,"inputRef",e)},queryList:function(e){return t.queryList=e}},t.renderQueryList=function(e){var n,i=t.props,u=i.fill,l=i.tagInputProps,c=void 0===l?{}:l,d=i.popoverProps,f=void 0===d?{}:d,m=i.selectedItems,v=void 0===m?[]:m,h=i.placeholder,I=e.handlePaste,y=e.handleKeyDown,O=e.handleKeyUp;u&&(f.fill=!0,c.fill=!0);var P=Object(r.__assign)(Object(r.__assign)({},c.inputProps),{className:s()(null===(n=c.inputProps)||void 0===n?void 0:n.className,p.Classes.MULTISELECT_TAG_INPUT_INPUT)});return o.createElement(a.Popover,Object(r.__assign)({autoFocus:!1,canEscapeKeyClose:!0,enforceFocus:!1,isOpen:t.state.isOpen,position:a.Position.BOTTOM_LEFT},f,{className:s()(e.className,f.className),interactionKind:a.PopoverInteractionKind.CLICK,onInteraction:t.handlePopoverInteraction,popoverClassName:s()(p.Classes.MULTISELECT_POPOVER,f.popoverClassName),onOpened:t.handlePopoverOpened}),o.createElement("div",{onKeyDown:t.getTagInputKeyDownHandler(y),onKeyUp:t.getTagInputKeyUpHandler(O)},o.createElement(a.TagInput,Object(r.__assign)({placeholder:h},c,{className:s()(p.Classes.MULTISELECT,c.className),inputRef:t.refHandlers.input,inputProps:P,inputValue:e.query,onAdd:function(e,t){"paste"===t&&I(e)},onInputChange:e.handleQueryChange,values:v.map(t.props.tagRenderer)}))),o.createElement("div",{onKeyDown:y,onKeyUp:O},e.itemList))},t.handleItemSelect=function(e,n){null!=t.input&&t.input.focus(),a.Utils.safeInvoke(t.props.onItemSelect,e,n)},t.handleQueryChange=function(e,n){t.setState({isOpen:e.length>0||!t.props.openOnKeyDown}),a.Utils.safeInvoke(t.props.onQueryChange,e,n)},t.handlePopoverInteraction=function(e){return requestAnimationFrame((function(){var n,r,i=t.input===document.activeElement;null==t.input||i?t.props.openOnKeyDown||t.setState({isOpen:!0}):t.setState({isOpen:!1}),null===(r=null===(n=t.props.popoverProps)||void 0===n?void 0:n.onInteraction)||void 0===r||r.call(n,e)}))},t.handlePopoverOpened=function(e){null!=t.queryList&&t.queryList.scrollActiveItemIntoView(),a.Utils.safeInvokeMember(t.props.popoverProps,"onOpened",e)},t.getTagInputKeyDownHandler=function(e){return function(n){var r=n.which;r===a.Keys.ESCAPE||r===a.Keys.TAB?(null!=t.input&&t.input.blur(),t.setState({isOpen:!1})):r!==a.Keys.BACKSPACE&&r!==a.Keys.ARROW_LEFT&&r!==a.Keys.ARROW_RIGHT&&t.setState({isOpen:!0});var i=null!=n.target.closest("."+a.Classes.TAG_REMOVE);t.state.isOpen&&!i&&a.Utils.safeInvoke(e,n)}},t.getTagInputKeyUpHandler=function(e){return function(n){var r=n.target.classList.contains(p.Classes.MULTISELECT_TAG_INPUT_INPUT);t.state.isOpen&&r&&a.Utils.safeInvoke(e,n)}},t}return Object(r.__extends)(t,e),t.ofType=function(){return t},t.prototype.render=function(){var e=this.props,t=(e.openOnKeyDown,e.popoverProps,e.tagInputProps,Object(r.__rest)(e,["openOnKeyDown","popoverProps","tagInputProps"]));return o.createElement(this.TypedQueryList,Object(r.__assign)({},t,{onItemSelect:this.handleItemSelect,onQueryChange:this.handleQueryChange,ref:this.refHandlers.queryList,renderer:this.renderQueryList}))},t.displayName=a.DISPLAYNAME_PREFIX+".MultiSelect",t.defaultProps={fill:!1,placeholder:"Search..."},t}(o.PureComponent),P=function(e){function t(){var t,n=e.apply(this,arguments)||this;return n.state={isOpen:!1},n.TypedQueryList=d.ofType(),n.inputEl=null,n.queryList=null,n.refHandlers={input:Object(a.isRefObject)(null===(t=n.props.inputProps)||void 0===t?void 0:t.inputRef)?n.inputEl=n.props.inputProps.inputRef:function(e){var t,r;n.inputEl=e,null===(r=null===(t=n.props.inputProps)||void 0===t?void 0:t.inputRef)||void 0===r||r(e)},queryList:function(e){return n.queryList=e}},n.renderQueryList=function(e){var t=n.props,i=t.filterable,u=void 0===i||i,l=t.disabled,c=void 0!==l&&l,d=t.inputProps,f=void 0===d?{}:d,m=t.popoverProps,v=void 0===m?{}:m,h=o.createElement(a.InputGroup,Object(r.__assign)({leftIcon:"search",placeholder:"Filter...",rightElement:n.maybeRenderClearButton(e.query)},f,{inputRef:n.refHandlers.input,onChange:e.handleQueryChange,value:e.query})),I=e.handleKeyDown,y=e.handleKeyUp;return o.createElement(a.Popover,Object(r.__assign)({autoFocus:!1,enforceFocus:!1,isOpen:n.state.isOpen,disabled:c,position:a.Position.BOTTOM_LEFT},v,{className:s()(e.className,v.className),onInteraction:n.handlePopoverInteraction,popoverClassName:s()(p.Classes.SELECT_POPOVER,v.popoverClassName),onOpening:n.handlePopoverOpening,onOpened:n.handlePopoverOpened,onClosing:n.handlePopoverClosing}),o.createElement("div",{onKeyDown:n.state.isOpen?I:n.handleTargetKeyDown,onKeyUp:n.state.isOpen?y:void 0},n.props.children),o.createElement("div",{onKeyDown:I,onKeyUp:y},u?h:void 0,e.itemList))},n.handleTargetKeyDown=function(e){e.which!==a.Keys.ARROW_UP&&e.which!==a.Keys.ARROW_DOWN||(e.preventDefault(),n.setState({isOpen:!0}))},n.handleItemSelect=function(e,t){n.setState({isOpen:!1}),a.Utils.safeInvoke(n.props.onItemSelect,e,t)},n.handlePopoverInteraction=function(e){n.setState({isOpen:e}),a.Utils.safeInvokeMember(n.props.popoverProps,"onInteraction",e)},n.handlePopoverOpening=function(e){n.previousFocusedElement=document.activeElement,n.props.resetOnClose&&n.resetQuery(),a.Utils.safeInvokeMember(n.props.popoverProps,"onOpening",e)},n.handlePopoverOpened=function(e){null!=n.queryList&&n.queryList.scrollActiveItemIntoView(),requestAnimationFrame((function(){var e=n.props.inputProps;!1!==(void 0===e?{}:e).autoFocus&&null!=n.inputEl&&Object(a.getRef)(n.inputEl).focus()})),a.Utils.safeInvokeMember(n.props.popoverProps,"onOpened",e)},n.handlePopoverClosing=function(e){requestAnimationFrame((function(){void 0!==n.previousFocusedElement&&(n.previousFocusedElement.focus(),n.previousFocusedElement=void 0)})),a.Utils.safeInvokeMember(n.props.popoverProps,"onClosing",e)},n.resetQuery=function(){return n.queryList&&n.queryList.setQuery("",!0)},n}return Object(r.__extends)(t,e),t.ofType=function(){return t},t.prototype.render=function(){var e=this.props,t=(e.filterable,e.inputProps,e.popoverProps,Object(r.__rest)(e,["filterable","inputProps","popoverProps"]));return o.createElement(this.TypedQueryList,Object(r.__assign)({},t,{onItemSelect:this.handleItemSelect,ref:this.refHandlers.queryList,renderer:this.renderQueryList}))},t.prototype.componentDidUpdate=function(e,t){this.state.isOpen&&!t.isOpen&&null!=this.queryList&&this.queryList.scrollActiveItemIntoView()},t.prototype.maybeRenderClearButton=function(e){return e.length>0?o.createElement(a.Button,{icon:"cross",minimal:!0,onClick:this.resetQuery}):void 0},t.displayName=a.DISPLAYNAME_PREFIX+".Select",t}(o.PureComponent),g=function(e){function t(){var t,n=e.apply(this,arguments)||this;return n.state={isOpen:null!=n.props.popoverProps&&n.props.popoverProps.isOpen||!1,selectedItem:n.getInitialSelectedItem()},n.TypedQueryList=d.ofType(),n.inputEl=null,n.queryList=null,n.refHandlers={input:Object(a.isRefObject)(null===(t=n.props.inputProps)||void 0===t?void 0:t.inputRef)?n.inputEl=n.props.inputProps.inputRef:function(e){var t,r;n.inputEl=e,null===(r=null===(t=n.props.inputProps)||void 0===t?void 0:t.inputRef)||void 0===r||r(e)},queryList:function(e){return n.queryList=e}},n.renderQueryList=function(e){var t=n.props,i=t.fill,u=t.inputProps,l=void 0===u?{}:u,c=t.popoverProps,d=void 0===c?{}:c,f=n.state,m=f.isOpen,v=f.selectedItem,h=e.handleKeyDown,I=e.handleKeyUp,y=l.autoComplete,O=void 0===y?"off":y,P=l.placeholder,g=void 0===P?"Search...":P,b=v?n.props.inputValueRenderer(v):"",C=m&&b?b:g,E=m?e.query:b||(n.props.resetOnClose?"":e.query);return i&&(d.fill=!0,l.fill=!0),o.createElement(a.Popover,Object(r.__assign)({autoFocus:!1,enforceFocus:!1,isOpen:m,position:a.Position.BOTTOM_LEFT},d,{className:s()(e.className,d.className),interactionKind:a.PopoverInteractionKind.CLICK,onInteraction:n.handlePopoverInteraction,popoverClassName:s()(p.Classes.SELECT_POPOVER,d.popoverClassName),onOpening:n.handlePopoverOpening,onOpened:n.handlePopoverOpened}),o.createElement(a.InputGroup,Object(r.__assign)({autoComplete:O,disabled:n.props.disabled},l,{inputRef:n.refHandlers.input,onChange:e.handleQueryChange,onFocus:n.handleInputFocus,onKeyDown:n.getTargetKeyDownHandler(h),onKeyUp:n.getTargetKeyUpHandler(I),placeholder:C,value:E})),o.createElement("div",{onKeyDown:h,onKeyUp:I},e.itemList))},n.selectText=function(){requestAnimationFrame((function(){if(null!=n.inputEl){var e=Object(a.getRef)(n.inputEl);e.setSelectionRange(0,e.value.length)}}))},n.handleInputFocus=function(e){n.selectText(),n.props.openOnKeyDown||n.setState({isOpen:!0}),a.Utils.safeInvokeMember(n.props.inputProps,"onFocus",e)},n.handleItemSelect=function(e,t){var r;n.props.closeOnSelect?(null!=n.inputEl&&Object(a.getRef)(n.inputEl).blur(),r=!1):(null!=n.inputEl&&Object(a.getRef)(n.inputEl).focus(),n.selectText(),r=!0),void 0===n.props.selectedItem?n.setState({isOpen:r,selectedItem:e}):n.setState({isOpen:r}),a.Utils.safeInvoke(n.props.onItemSelect,e,t)},n.handlePopoverInteraction=function(e){return requestAnimationFrame((function(){var t=Object(a.getRef)(n.inputEl)===document.activeElement;null==n.inputEl||t||n.setState({isOpen:!1}),a.Utils.safeInvokeMember(n.props.popoverProps,"onInteraction",e)}))},n.handlePopoverOpening=function(e){n.props.resetOnClose&&n.queryList&&n.queryList.setQuery("",!0),a.Utils.safeInvokeMember(n.props.popoverProps,"onOpening",e)},n.handlePopoverOpened=function(e){null!=n.queryList&&n.queryList.scrollActiveItemIntoView(),a.Utils.safeInvokeMember(n.props.popoverProps,"onOpened",e)},n.getTargetKeyDownHandler=function(e){return function(t){var r=t.which;r===a.Keys.ESCAPE||r===a.Keys.TAB?(null!=n.inputEl&&Object(a.getRef)(n.inputEl).blur(),n.setState({isOpen:!1})):n.props.openOnKeyDown&&r!==a.Keys.BACKSPACE&&r!==a.Keys.ARROW_LEFT&&r!==a.Keys.ARROW_RIGHT&&n.setState({isOpen:!0}),n.state.isOpen&&a.Utils.safeInvoke(e,t),a.Utils.safeInvokeMember(n.props.inputProps,"onKeyDown",t)}},n.getTargetKeyUpHandler=function(e){return function(t){n.state.isOpen&&a.Utils.safeInvoke(e,t),a.Utils.safeInvokeMember(n.props.inputProps,"onKeyUp",t)}},n}return Object(r.__extends)(t,e),t.ofType=function(){return t},t.prototype.render=function(){var e,t=this.props,n=(t.disabled,t.inputProps,t.popoverProps,Object(r.__rest)(t,["disabled","inputProps","popoverProps"]));return o.createElement(this.TypedQueryList,Object(r.__assign)({},n,{initialActiveItem:null!==(e=this.props.selectedItem)&&void 0!==e?e:void 0,onItemSelect:this.handleItemSelect,ref:this.refHandlers.queryList,renderer:this.renderQueryList}))},t.prototype.componentDidUpdate=function(e,t){var n,r,i=this;void 0!==this.props.selectedItem&&this.props.selectedItem!==this.state.selectedItem&&this.setState({selectedItem:this.props.selectedItem}),!1===this.state.isOpen&&!0===t.isOpen&&setTimeout((function(){i.maybeResetActiveItemToSelectedItem()}),null!==(r=null===(n=this.props.popoverProps)||void 0===n?void 0:n.transitionDuration)&&void 0!==r?r:a.Popover.defaultProps.transitionDuration),this.state.isOpen&&!t.isOpen&&null!=this.queryList&&this.queryList.scrollActiveItemIntoView()},t.prototype.getInitialSelectedItem=function(){return void 0!==this.props.selectedItem?this.props.selectedItem:void 0!==this.props.defaultSelectedItem?this.props.defaultSelectedItem:null},t.prototype.maybeResetActiveItemToSelectedItem=function(){var e,t=void 0===this.props.activeItem&&null!==this.state.selectedItem&&!this.props.resetOnSelect;null!==this.queryList&&t&&this.queryList.setActiveItem(null!==(e=this.props.selectedItem)&&void 0!==e?e:this.state.selectedItem)},t.displayName=a.DISPLAYNAME_PREFIX+".Suggest",t.defaultProps={closeOnSelect:!0,fill:!1,openOnKeyDown:!1,resetOnClose:!1},t}(o.PureComponent)},function(e,t,n){e.exports=n(13)},function(e,t,n){"use strict";n.r(t);var r=n(3);for(var i in r)["default"].indexOf(i)<0&&function(e){n.d(t,e,(function(){return r[e]}))}(i);var s=n(11);n.d(t,"Omnibar",(function(){return s.b})),n.d(t,"QueryList",(function(){return s.c})),n.d(t,"getFirstEnabledItem",(function(){return s.f})),n.d(t,"MultiSelect",(function(){return s.a})),n.d(t,"Select",(function(){return s.d})),n.d(t,"Suggest",(function(){return s.e}))}])})); |
@@ -97,2 +97,4 @@ "use strict"; | ||
return function (e) { | ||
// HACKHACK: https://github.com/palantir/blueprint/issues/4165 | ||
// eslint-disable-next-line deprecation/deprecation | ||
var which = e.which; | ||
@@ -99,0 +101,0 @@ if (which === core_1.Keys.ESCAPE || which === core_1.Keys.TAB) { |
@@ -57,2 +57,4 @@ "use strict"; | ||
// open popover when arrow key pressed on target while closed | ||
// HACKHACK: https://github.com/palantir/blueprint/issues/4165 | ||
// eslint-disable-next-line deprecation/deprecation | ||
if (event.which === core_1.Keys.ARROW_UP || event.which === core_1.Keys.ARROW_DOWN) { | ||
@@ -59,0 +61,0 @@ event.preventDefault(); |
@@ -142,2 +142,4 @@ "use strict"; | ||
return function (evt) { | ||
// HACKHACK: https://github.com/palantir/blueprint/issues/4165 | ||
// eslint-disable-next-line deprecation/deprecation | ||
var which = evt.which; | ||
@@ -144,0 +146,0 @@ if (which === core_1.Keys.ESCAPE || which === core_1.Keys.TAB) { |
@@ -94,2 +94,4 @@ /* | ||
return function (e) { | ||
// HACKHACK: https://github.com/palantir/blueprint/issues/4165 | ||
// eslint-disable-next-line deprecation/deprecation | ||
var which = e.which; | ||
@@ -96,0 +98,0 @@ if (which === Keys.ESCAPE || which === Keys.TAB) { |
@@ -54,2 +54,4 @@ /* | ||
// open popover when arrow key pressed on target while closed | ||
// HACKHACK: https://github.com/palantir/blueprint/issues/4165 | ||
// eslint-disable-next-line deprecation/deprecation | ||
if (event.which === Keys.ARROW_UP || event.which === Keys.ARROW_DOWN) { | ||
@@ -56,0 +58,0 @@ event.preventDefault(); |
@@ -139,2 +139,4 @@ /* | ||
return function (evt) { | ||
// HACKHACK: https://github.com/palantir/blueprint/issues/4165 | ||
// eslint-disable-next-line deprecation/deprecation | ||
var which = evt.which; | ||
@@ -141,0 +143,0 @@ if (which === Keys.ESCAPE || which === Keys.TAB) { |
@@ -21,34 +21,30 @@ /* | ||
import { QueryList } from "../query-list/queryList"; | ||
let Omnibar = /** @class */ (() => { | ||
class Omnibar extends React.PureComponent { | ||
constructor() { | ||
super(...arguments); | ||
this.TypedQueryList = QueryList.ofType(); | ||
this.renderQueryList = (listProps) => { | ||
const { inputProps = {}, isOpen, overlayProps = {} } = this.props; | ||
const { handleKeyDown, handleKeyUp } = listProps; | ||
const handlers = isOpen ? { onKeyDown: handleKeyDown, onKeyUp: handleKeyUp } : {}; | ||
return (React.createElement(Overlay, Object.assign({ hasBackdrop: true }, overlayProps, { isOpen: isOpen, className: classNames(Classes.OMNIBAR_OVERLAY, overlayProps.className), onClose: this.handleOverlayClose }), | ||
React.createElement("div", Object.assign({ className: classNames(Classes.OMNIBAR, listProps.className) }, handlers), | ||
React.createElement(InputGroup, Object.assign({ autoFocus: true, large: true, leftIcon: "search", placeholder: "Search..." }, inputProps, { onChange: listProps.handleQueryChange, value: listProps.query })), | ||
listProps.itemList))); | ||
}; | ||
this.handleOverlayClose = (event) => { | ||
Utils.safeInvokeMember(this.props.overlayProps, "onClose", event); | ||
Utils.safeInvoke(this.props.onClose, event); | ||
}; | ||
} | ||
static ofType() { | ||
return Omnibar; | ||
} | ||
render() { | ||
// omit props specific to this component, spread the rest. | ||
const { initialContent = null, isOpen, inputProps, overlayProps, ...restProps } = this.props; | ||
return React.createElement(this.TypedQueryList, Object.assign({}, restProps, { initialContent: initialContent, renderer: this.renderQueryList })); | ||
} | ||
export class Omnibar extends React.PureComponent { | ||
constructor() { | ||
super(...arguments); | ||
this.TypedQueryList = QueryList.ofType(); | ||
this.renderQueryList = (listProps) => { | ||
const { inputProps = {}, isOpen, overlayProps = {} } = this.props; | ||
const { handleKeyDown, handleKeyUp } = listProps; | ||
const handlers = isOpen ? { onKeyDown: handleKeyDown, onKeyUp: handleKeyUp } : {}; | ||
return (React.createElement(Overlay, Object.assign({ hasBackdrop: true }, overlayProps, { isOpen: isOpen, className: classNames(Classes.OMNIBAR_OVERLAY, overlayProps.className), onClose: this.handleOverlayClose }), | ||
React.createElement("div", Object.assign({ className: classNames(Classes.OMNIBAR, listProps.className) }, handlers), | ||
React.createElement(InputGroup, Object.assign({ autoFocus: true, large: true, leftIcon: "search", placeholder: "Search..." }, inputProps, { onChange: listProps.handleQueryChange, value: listProps.query })), | ||
listProps.itemList))); | ||
}; | ||
this.handleOverlayClose = (event) => { | ||
Utils.safeInvokeMember(this.props.overlayProps, "onClose", event); | ||
Utils.safeInvoke(this.props.onClose, event); | ||
}; | ||
} | ||
Omnibar.displayName = `${DISPLAYNAME_PREFIX}.Omnibar`; | ||
return Omnibar; | ||
})(); | ||
export { Omnibar }; | ||
static ofType() { | ||
return Omnibar; | ||
} | ||
render() { | ||
// omit props specific to this component, spread the rest. | ||
const { initialContent = null, isOpen, inputProps, overlayProps, ...restProps } = this.props; | ||
return React.createElement(this.TypedQueryList, Object.assign({}, restProps, { initialContent: initialContent, renderer: this.renderQueryList })); | ||
} | ||
} | ||
Omnibar.displayName = `${DISPLAYNAME_PREFIX}.Omnibar`; | ||
//# sourceMappingURL=omnibar.js.map |
@@ -19,366 +19,362 @@ /* | ||
import { executeItemsEqual, getActiveItem, getCreateNewItem, isCreateNewItem, renderFilteredItems, } from "../../common"; | ||
let QueryList = /** @class */ (() => { | ||
class QueryList extends AbstractComponent2 { | ||
constructor(props, context) { | ||
super(props, context); | ||
this.refHandlers = { | ||
itemsParent: (ref) => (this.itemsParentRef = ref), | ||
}; | ||
/** | ||
* Flag indicating that we should check whether selected item is in viewport | ||
* after rendering, typically because of keyboard change. Set to `true` when | ||
* manipulating state in a way that may cause active item to scroll away. | ||
*/ | ||
this.shouldCheckActiveItemInViewport = false; | ||
/** | ||
* The item that we expect to be the next selected active item (based on click | ||
* or key interactions). When scrollToActiveItem = false, used to detect if | ||
* an unexpected external change to the active item has been made. | ||
*/ | ||
this.expectedNextActiveItem = null; | ||
/** | ||
* Flag which is set to true while in between an ENTER "keydown" event and its | ||
* corresponding "keyup" event. | ||
* | ||
* When entering text via an IME (https://en.wikipedia.org/wiki/Input_method), | ||
* the ENTER key is pressed to confirm the character(s) to be input from a list | ||
* of options. The operating system intercepts the ENTER "keydown" event and | ||
* prevents it from propagating to the application, but "keyup" is still | ||
* fired, triggering a spurious event which this component does not expect. | ||
* | ||
* To work around this quirk, we keep track of "real" key presses by setting | ||
* this flag in handleKeyDown. | ||
*/ | ||
this.isEnterKeyPressed = false; | ||
/** default `itemListRenderer` implementation */ | ||
this.renderItemList = (listProps) => { | ||
const { initialContent, noResults } = this.props; | ||
// omit noResults if createNewItemFromQuery and createNewItemRenderer are both supplied, and query is not empty | ||
const maybeNoResults = this.isCreateItemRendered() ? null : noResults; | ||
const menuContent = renderFilteredItems(listProps, maybeNoResults, initialContent); | ||
const createItemView = this.isCreateItemRendered() | ||
? this.renderCreateItemMenuItem(this.state.query.trim()) | ||
: null; | ||
if (menuContent == null && createItemView == null) { | ||
return null; | ||
} | ||
return (React.createElement(Menu, { ulRef: listProps.itemsParentRef }, | ||
menuContent, | ||
createItemView)); | ||
}; | ||
/** wrapper around `itemRenderer` to inject props */ | ||
this.renderItem = (item, index) => { | ||
if (this.props.disabled !== true) { | ||
const { activeItem, query } = this.state; | ||
const matchesPredicate = this.state.filteredItems.indexOf(item) >= 0; | ||
const modifiers = { | ||
active: executeItemsEqual(this.props.itemsEqual, getActiveItem(activeItem), item), | ||
disabled: isItemDisabled(item, index, this.props.itemDisabled), | ||
matchesPredicate, | ||
}; | ||
return this.props.itemRenderer(item, { | ||
handleClick: e => this.handleItemSelect(item, e), | ||
index, | ||
modifiers, | ||
query, | ||
}); | ||
} | ||
export class QueryList extends AbstractComponent2 { | ||
constructor(props, context) { | ||
super(props, context); | ||
this.refHandlers = { | ||
itemsParent: (ref) => (this.itemsParentRef = ref), | ||
}; | ||
/** | ||
* Flag indicating that we should check whether selected item is in viewport | ||
* after rendering, typically because of keyboard change. Set to `true` when | ||
* manipulating state in a way that may cause active item to scroll away. | ||
*/ | ||
this.shouldCheckActiveItemInViewport = false; | ||
/** | ||
* The item that we expect to be the next selected active item (based on click | ||
* or key interactions). When scrollToActiveItem = false, used to detect if | ||
* an unexpected external change to the active item has been made. | ||
*/ | ||
this.expectedNextActiveItem = null; | ||
/** | ||
* Flag which is set to true while in between an ENTER "keydown" event and its | ||
* corresponding "keyup" event. | ||
* | ||
* When entering text via an IME (https://en.wikipedia.org/wiki/Input_method), | ||
* the ENTER key is pressed to confirm the character(s) to be input from a list | ||
* of options. The operating system intercepts the ENTER "keydown" event and | ||
* prevents it from propagating to the application, but "keyup" is still | ||
* fired, triggering a spurious event which this component does not expect. | ||
* | ||
* To work around this quirk, we keep track of "real" key presses by setting | ||
* this flag in handleKeyDown. | ||
*/ | ||
this.isEnterKeyPressed = false; | ||
/** default `itemListRenderer` implementation */ | ||
this.renderItemList = (listProps) => { | ||
const { initialContent, noResults } = this.props; | ||
// omit noResults if createNewItemFromQuery and createNewItemRenderer are both supplied, and query is not empty | ||
const maybeNoResults = this.isCreateItemRendered() ? null : noResults; | ||
const menuContent = renderFilteredItems(listProps, maybeNoResults, initialContent); | ||
const createItemView = this.isCreateItemRendered() | ||
? this.renderCreateItemMenuItem(this.state.query.trim()) | ||
: null; | ||
if (menuContent == null && createItemView == null) { | ||
return null; | ||
}; | ||
this.renderCreateItemMenuItem = (query) => { | ||
const { activeItem } = this.state; | ||
const handleClick = evt => { | ||
this.handleItemCreate(query, evt); | ||
} | ||
return (React.createElement(Menu, { ulRef: listProps.itemsParentRef }, | ||
menuContent, | ||
createItemView)); | ||
}; | ||
/** wrapper around `itemRenderer` to inject props */ | ||
this.renderItem = (item, index) => { | ||
if (this.props.disabled !== true) { | ||
const { activeItem, query } = this.state; | ||
const matchesPredicate = this.state.filteredItems.indexOf(item) >= 0; | ||
const modifiers = { | ||
active: executeItemsEqual(this.props.itemsEqual, getActiveItem(activeItem), item), | ||
disabled: isItemDisabled(item, index, this.props.itemDisabled), | ||
matchesPredicate, | ||
}; | ||
const isActive = isCreateNewItem(activeItem); | ||
return Utils.safeInvoke(this.props.createNewItemRenderer, query, isActive, handleClick); | ||
return this.props.itemRenderer(item, { | ||
handleClick: e => this.handleItemSelect(item, e), | ||
index, | ||
modifiers, | ||
query, | ||
}); | ||
} | ||
return null; | ||
}; | ||
this.renderCreateItemMenuItem = (query) => { | ||
const { activeItem } = this.state; | ||
const handleClick = evt => { | ||
this.handleItemCreate(query, evt); | ||
}; | ||
this.handleItemCreate = (query, evt) => { | ||
// we keep a cached createNewItem in state, but might as well recompute | ||
// the result just to be sure it's perfectly in sync with the query. | ||
const item = Utils.safeInvoke(this.props.createNewItemFromQuery, query); | ||
if (item != null) { | ||
Utils.safeInvoke(this.props.onItemSelect, item, evt); | ||
this.maybeResetQuery(); | ||
} | ||
}; | ||
this.handleItemSelect = (item, event) => { | ||
this.setActiveItem(item); | ||
Utils.safeInvoke(this.props.onItemSelect, item, event); | ||
const isActive = isCreateNewItem(activeItem); | ||
return Utils.safeInvoke(this.props.createNewItemRenderer, query, isActive, handleClick); | ||
}; | ||
this.handleItemCreate = (query, evt) => { | ||
// we keep a cached createNewItem in state, but might as well recompute | ||
// the result just to be sure it's perfectly in sync with the query. | ||
const item = Utils.safeInvoke(this.props.createNewItemFromQuery, query); | ||
if (item != null) { | ||
Utils.safeInvoke(this.props.onItemSelect, item, evt); | ||
this.maybeResetQuery(); | ||
}; | ||
this.handlePaste = (queries) => { | ||
const { createNewItemFromQuery, onItemsPaste } = this.props; | ||
let nextActiveItem; | ||
const nextQueries = []; | ||
// Find an exising item that exactly matches each pasted value, or | ||
// create a new item if possible. Ignore unmatched values if creating | ||
// items is disabled. | ||
const pastedItemsToEmit = []; | ||
for (const query of queries) { | ||
const equalItem = getMatchingItem(query, this.props); | ||
if (equalItem !== undefined) { | ||
nextActiveItem = equalItem; | ||
pastedItemsToEmit.push(equalItem); | ||
} | ||
else if (this.canCreateItems()) { | ||
const newItem = Utils.safeInvoke(createNewItemFromQuery, query); | ||
if (newItem !== undefined) { | ||
pastedItemsToEmit.push(newItem); | ||
} | ||
} | ||
else { | ||
nextQueries.push(query); | ||
} | ||
} | ||
}; | ||
this.handleItemSelect = (item, event) => { | ||
this.setActiveItem(item); | ||
Utils.safeInvoke(this.props.onItemSelect, item, event); | ||
this.maybeResetQuery(); | ||
}; | ||
this.handlePaste = (queries) => { | ||
const { createNewItemFromQuery, onItemsPaste } = this.props; | ||
let nextActiveItem; | ||
const nextQueries = []; | ||
// Find an exising item that exactly matches each pasted value, or | ||
// create a new item if possible. Ignore unmatched values if creating | ||
// items is disabled. | ||
const pastedItemsToEmit = []; | ||
for (const query of queries) { | ||
const equalItem = getMatchingItem(query, this.props); | ||
if (equalItem !== undefined) { | ||
nextActiveItem = equalItem; | ||
pastedItemsToEmit.push(equalItem); | ||
} | ||
// UX nicety: combine all unmatched queries into a single | ||
// comma-separated query in the input, so we don't lose any information. | ||
// And don't reset the active item; we'll do that ourselves below. | ||
this.setQuery(nextQueries.join(", "), false); | ||
// UX nicety: update the active item if we matched with at least one | ||
// existing item. | ||
if (nextActiveItem !== undefined) { | ||
this.setActiveItem(nextActiveItem); | ||
} | ||
Utils.safeInvoke(onItemsPaste, pastedItemsToEmit); | ||
}; | ||
this.handleKeyDown = (event) => { | ||
const { keyCode } = event; | ||
if (keyCode === Keys.ARROW_UP || keyCode === Keys.ARROW_DOWN) { | ||
event.preventDefault(); | ||
const nextActiveItem = this.getNextActiveItem(keyCode === Keys.ARROW_UP ? -1 : 1); | ||
if (nextActiveItem != null) { | ||
this.setActiveItem(nextActiveItem); | ||
else if (this.canCreateItems()) { | ||
const newItem = Utils.safeInvoke(createNewItemFromQuery, query); | ||
if (newItem !== undefined) { | ||
pastedItemsToEmit.push(newItem); | ||
} | ||
} | ||
else if (keyCode === Keys.ENTER) { | ||
this.isEnterKeyPressed = true; | ||
else { | ||
nextQueries.push(query); | ||
} | ||
Utils.safeInvoke(this.props.onKeyDown, event); | ||
}; | ||
this.handleKeyUp = (event) => { | ||
const { onKeyUp } = this.props; | ||
const { activeItem } = this.state; | ||
if (event.keyCode === Keys.ENTER && this.isEnterKeyPressed) { | ||
// We handle ENTER in keyup here to play nice with the Button component's keyboard | ||
// clicking. Button is commonly used as the only child of Select. If we were to | ||
// instead process ENTER on keydown, then Button would click itself on keyup and | ||
// the Select popover would re-open. | ||
event.preventDefault(); | ||
if (activeItem == null || isCreateNewItem(activeItem)) { | ||
this.handleItemCreate(this.state.query, event); | ||
} | ||
else { | ||
this.handleItemSelect(activeItem, event); | ||
} | ||
this.isEnterKeyPressed = false; | ||
} | ||
Utils.safeInvoke(onKeyUp, event); | ||
}; | ||
this.handleInputQueryChange = (event) => { | ||
const query = event == null ? "" : event.target.value; | ||
this.setQuery(query); | ||
Utils.safeInvoke(this.props.onQueryChange, query, event); | ||
}; | ||
const { query = "" } = props; | ||
const createNewItem = Utils.safeInvoke(props.createNewItemFromQuery, query); | ||
const filteredItems = getFilteredItems(query, props); | ||
this.state = { | ||
activeItem: props.activeItem !== undefined | ||
? props.activeItem | ||
: props.initialActiveItem ?? getFirstEnabledItem(filteredItems, props.itemDisabled), | ||
createNewItem, | ||
filteredItems, | ||
query, | ||
}; | ||
} | ||
static ofType() { | ||
return QueryList; | ||
} | ||
render() { | ||
const { className, items, renderer, itemListRenderer = this.renderItemList } = this.props; | ||
const { createNewItem, ...spreadableState } = this.state; | ||
return renderer({ | ||
...spreadableState, | ||
className, | ||
handleItemSelect: this.handleItemSelect, | ||
handleKeyDown: this.handleKeyDown, | ||
handleKeyUp: this.handleKeyUp, | ||
handlePaste: this.handlePaste, | ||
handleQueryChange: this.handleInputQueryChange, | ||
itemList: itemListRenderer({ | ||
...spreadableState, | ||
items, | ||
itemsParentRef: this.refHandlers.itemsParent, | ||
renderItem: this.renderItem, | ||
}), | ||
}); | ||
} | ||
componentDidUpdate(prevProps) { | ||
if (this.props.activeItem !== undefined && this.props.activeItem !== this.state.activeItem) { | ||
this.shouldCheckActiveItemInViewport = true; | ||
this.setState({ activeItem: this.props.activeItem }); | ||
} | ||
if (this.props.query != null && this.props.query !== prevProps.query) { | ||
// new query | ||
this.setQuery(this.props.query, this.props.resetOnQuery, this.props); | ||
// UX nicety: combine all unmatched queries into a single | ||
// comma-separated query in the input, so we don't lose any information. | ||
// And don't reset the active item; we'll do that ourselves below. | ||
this.setQuery(nextQueries.join(", "), false); | ||
// UX nicety: update the active item if we matched with at least one | ||
// existing item. | ||
if (nextActiveItem !== undefined) { | ||
this.setActiveItem(nextActiveItem); | ||
} | ||
else if ( | ||
// same query (or uncontrolled query), but items in the list changed | ||
!Utils.shallowCompareKeys(this.props, prevProps, { | ||
include: ["items", "itemListPredicate", "itemPredicate"], | ||
})) { | ||
this.setQuery(this.state.query); | ||
Utils.safeInvoke(onItemsPaste, pastedItemsToEmit); | ||
}; | ||
this.handleKeyDown = (event) => { | ||
const { keyCode } = event; | ||
if (keyCode === Keys.ARROW_UP || keyCode === Keys.ARROW_DOWN) { | ||
event.preventDefault(); | ||
const nextActiveItem = this.getNextActiveItem(keyCode === Keys.ARROW_UP ? -1 : 1); | ||
if (nextActiveItem != null) { | ||
this.setActiveItem(nextActiveItem); | ||
} | ||
} | ||
if (this.shouldCheckActiveItemInViewport) { | ||
// update scroll position immediately before repaint so DOM is accurate | ||
// (latest filteredItems) and to avoid flicker. | ||
requestAnimationFrame(() => this.scrollActiveItemIntoView()); | ||
// reset the flag | ||
this.shouldCheckActiveItemInViewport = false; | ||
else if (keyCode === Keys.ENTER) { | ||
this.isEnterKeyPressed = true; | ||
} | ||
} | ||
scrollActiveItemIntoView() { | ||
const scrollToActiveItem = this.props.scrollToActiveItem !== false; | ||
const externalChangeToActiveItem = !executeItemsEqual(this.props.itemsEqual, getActiveItem(this.expectedNextActiveItem), getActiveItem(this.props.activeItem)); | ||
this.expectedNextActiveItem = null; | ||
if (!scrollToActiveItem && externalChangeToActiveItem) { | ||
return; | ||
} | ||
const activeElement = this.getActiveElement(); | ||
if (this.itemsParentRef != null && activeElement != null) { | ||
const { offsetTop: activeTop, offsetHeight: activeHeight } = activeElement; | ||
const { offsetTop: parentOffsetTop, scrollTop: parentScrollTop, clientHeight: parentHeight, } = this.itemsParentRef; | ||
// compute padding on parent element to ensure we always leave space | ||
const { paddingTop, paddingBottom } = this.getItemsParentPadding(); | ||
// compute the two edges of the active item for comparison, including parent padding | ||
const activeBottomEdge = activeTop + activeHeight + paddingBottom - parentOffsetTop; | ||
const activeTopEdge = activeTop - paddingTop - parentOffsetTop; | ||
if (activeBottomEdge >= parentScrollTop + parentHeight) { | ||
// offscreen bottom: align bottom of item with bottom of viewport | ||
this.itemsParentRef.scrollTop = activeBottomEdge + activeHeight - parentHeight; | ||
Utils.safeInvoke(this.props.onKeyDown, event); | ||
}; | ||
this.handleKeyUp = (event) => { | ||
const { onKeyUp } = this.props; | ||
const { activeItem } = this.state; | ||
if (event.keyCode === Keys.ENTER && this.isEnterKeyPressed) { | ||
// We handle ENTER in keyup here to play nice with the Button component's keyboard | ||
// clicking. Button is commonly used as the only child of Select. If we were to | ||
// instead process ENTER on keydown, then Button would click itself on keyup and | ||
// the Select popover would re-open. | ||
event.preventDefault(); | ||
if (activeItem == null || isCreateNewItem(activeItem)) { | ||
this.handleItemCreate(this.state.query, event); | ||
} | ||
else if (activeTopEdge <= parentScrollTop) { | ||
// offscreen top: align top of item with top of viewport | ||
this.itemsParentRef.scrollTop = activeTopEdge - activeHeight; | ||
else { | ||
this.handleItemSelect(activeItem, event); | ||
} | ||
this.isEnterKeyPressed = false; | ||
} | ||
Utils.safeInvoke(onKeyUp, event); | ||
}; | ||
this.handleInputQueryChange = (event) => { | ||
const query = event == null ? "" : event.target.value; | ||
this.setQuery(query); | ||
Utils.safeInvoke(this.props.onQueryChange, query, event); | ||
}; | ||
const { query = "" } = props; | ||
const createNewItem = Utils.safeInvoke(props.createNewItemFromQuery, query); | ||
const filteredItems = getFilteredItems(query, props); | ||
this.state = { | ||
activeItem: props.activeItem !== undefined | ||
? props.activeItem | ||
: props.initialActiveItem ?? getFirstEnabledItem(filteredItems, props.itemDisabled), | ||
createNewItem, | ||
filteredItems, | ||
query, | ||
}; | ||
} | ||
static ofType() { | ||
return QueryList; | ||
} | ||
render() { | ||
const { className, items, renderer, itemListRenderer = this.renderItemList } = this.props; | ||
const { createNewItem, ...spreadableState } = this.state; | ||
return renderer({ | ||
...spreadableState, | ||
className, | ||
handleItemSelect: this.handleItemSelect, | ||
handleKeyDown: this.handleKeyDown, | ||
handleKeyUp: this.handleKeyUp, | ||
handlePaste: this.handlePaste, | ||
handleQueryChange: this.handleInputQueryChange, | ||
itemList: itemListRenderer({ | ||
...spreadableState, | ||
items, | ||
itemsParentRef: this.refHandlers.itemsParent, | ||
renderItem: this.renderItem, | ||
}), | ||
}); | ||
} | ||
componentDidUpdate(prevProps) { | ||
if (this.props.activeItem !== undefined && this.props.activeItem !== this.state.activeItem) { | ||
this.shouldCheckActiveItemInViewport = true; | ||
this.setState({ activeItem: this.props.activeItem }); | ||
} | ||
setQuery(query, resetActiveItem = this.props.resetOnQuery, props = this.props) { | ||
const { createNewItemFromQuery } = props; | ||
this.shouldCheckActiveItemInViewport = true; | ||
const hasQueryChanged = query !== this.state.query; | ||
if (hasQueryChanged) { | ||
Utils.safeInvoke(props.onQueryChange, query); | ||
if (this.props.query != null && this.props.query !== prevProps.query) { | ||
// new query | ||
this.setQuery(this.props.query, this.props.resetOnQuery, this.props); | ||
} | ||
else if ( | ||
// same query (or uncontrolled query), but items in the list changed | ||
!Utils.shallowCompareKeys(this.props, prevProps, { | ||
include: ["items", "itemListPredicate", "itemPredicate"], | ||
})) { | ||
this.setQuery(this.state.query); | ||
} | ||
if (this.shouldCheckActiveItemInViewport) { | ||
// update scroll position immediately before repaint so DOM is accurate | ||
// (latest filteredItems) and to avoid flicker. | ||
requestAnimationFrame(() => this.scrollActiveItemIntoView()); | ||
// reset the flag | ||
this.shouldCheckActiveItemInViewport = false; | ||
} | ||
} | ||
scrollActiveItemIntoView() { | ||
const scrollToActiveItem = this.props.scrollToActiveItem !== false; | ||
const externalChangeToActiveItem = !executeItemsEqual(this.props.itemsEqual, getActiveItem(this.expectedNextActiveItem), getActiveItem(this.props.activeItem)); | ||
this.expectedNextActiveItem = null; | ||
if (!scrollToActiveItem && externalChangeToActiveItem) { | ||
return; | ||
} | ||
const activeElement = this.getActiveElement(); | ||
if (this.itemsParentRef != null && activeElement != null) { | ||
const { offsetTop: activeTop, offsetHeight: activeHeight } = activeElement; | ||
const { offsetTop: parentOffsetTop, scrollTop: parentScrollTop, clientHeight: parentHeight, } = this.itemsParentRef; | ||
// compute padding on parent element to ensure we always leave space | ||
const { paddingTop, paddingBottom } = this.getItemsParentPadding(); | ||
// compute the two edges of the active item for comparison, including parent padding | ||
const activeBottomEdge = activeTop + activeHeight + paddingBottom - parentOffsetTop; | ||
const activeTopEdge = activeTop - paddingTop - parentOffsetTop; | ||
if (activeBottomEdge >= parentScrollTop + parentHeight) { | ||
// offscreen bottom: align bottom of item with bottom of viewport | ||
this.itemsParentRef.scrollTop = activeBottomEdge + activeHeight - parentHeight; | ||
} | ||
// Leading and trailing whitespace can be confusing to display, so we remove it when passing it | ||
// to functions dealing with data, like createNewItemFromQuery. But we need the unaltered user-typed | ||
// query to remain in state to be able to render controlled text inputs properly. | ||
const trimmedQuery = query.trim(); | ||
const filteredItems = getFilteredItems(trimmedQuery, props); | ||
const createNewItem = createNewItemFromQuery != null && trimmedQuery !== "" ? createNewItemFromQuery(trimmedQuery) : undefined; | ||
this.setState({ createNewItem, filteredItems, query }); | ||
// always reset active item if it's now filtered or disabled | ||
const activeIndex = this.getActiveIndex(filteredItems); | ||
const shouldUpdateActiveItem = resetActiveItem || | ||
activeIndex < 0 || | ||
isItemDisabled(getActiveItem(this.state.activeItem), activeIndex, props.itemDisabled); | ||
if (shouldUpdateActiveItem) { | ||
this.setActiveItem(getFirstEnabledItem(filteredItems, props.itemDisabled)); | ||
else if (activeTopEdge <= parentScrollTop) { | ||
// offscreen top: align top of item with top of viewport | ||
this.itemsParentRef.scrollTop = activeTopEdge - activeHeight; | ||
} | ||
} | ||
setActiveItem(activeItem) { | ||
this.expectedNextActiveItem = activeItem; | ||
if (this.props.activeItem === undefined) { | ||
// indicate that the active item may need to be scrolled into view after update. | ||
this.shouldCheckActiveItemInViewport = true; | ||
this.setState({ activeItem }); | ||
} | ||
} | ||
setQuery(query, resetActiveItem = this.props.resetOnQuery, props = this.props) { | ||
const { createNewItemFromQuery } = props; | ||
this.shouldCheckActiveItemInViewport = true; | ||
const hasQueryChanged = query !== this.state.query; | ||
if (hasQueryChanged) { | ||
Utils.safeInvoke(props.onQueryChange, query); | ||
} | ||
// Leading and trailing whitespace can be confusing to display, so we remove it when passing it | ||
// to functions dealing with data, like createNewItemFromQuery. But we need the unaltered user-typed | ||
// query to remain in state to be able to render controlled text inputs properly. | ||
const trimmedQuery = query.trim(); | ||
const filteredItems = getFilteredItems(trimmedQuery, props); | ||
const createNewItem = createNewItemFromQuery != null && trimmedQuery !== "" ? createNewItemFromQuery(trimmedQuery) : undefined; | ||
this.setState({ createNewItem, filteredItems, query }); | ||
// always reset active item if it's now filtered or disabled | ||
const activeIndex = this.getActiveIndex(filteredItems); | ||
const shouldUpdateActiveItem = resetActiveItem || | ||
activeIndex < 0 || | ||
isItemDisabled(getActiveItem(this.state.activeItem), activeIndex, props.itemDisabled); | ||
if (shouldUpdateActiveItem) { | ||
this.setActiveItem(getFirstEnabledItem(filteredItems, props.itemDisabled)); | ||
} | ||
} | ||
setActiveItem(activeItem) { | ||
this.expectedNextActiveItem = activeItem; | ||
if (this.props.activeItem === undefined) { | ||
// indicate that the active item may need to be scrolled into view after update. | ||
this.shouldCheckActiveItemInViewport = true; | ||
this.setState({ activeItem }); | ||
} | ||
if (isCreateNewItem(activeItem)) { | ||
Utils.safeInvoke(this.props.onActiveItemChange, null, true); | ||
} | ||
else { | ||
Utils.safeInvoke(this.props.onActiveItemChange, activeItem, false); | ||
} | ||
} | ||
getActiveElement() { | ||
const { activeItem } = this.state; | ||
if (this.itemsParentRef != null) { | ||
if (isCreateNewItem(activeItem)) { | ||
Utils.safeInvoke(this.props.onActiveItemChange, null, true); | ||
return this.itemsParentRef.children.item(this.state.filteredItems.length); | ||
} | ||
else { | ||
Utils.safeInvoke(this.props.onActiveItemChange, activeItem, false); | ||
const activeIndex = this.getActiveIndex(); | ||
return this.itemsParentRef.children.item(activeIndex); | ||
} | ||
} | ||
getActiveElement() { | ||
const { activeItem } = this.state; | ||
if (this.itemsParentRef != null) { | ||
if (isCreateNewItem(activeItem)) { | ||
return this.itemsParentRef.children.item(this.state.filteredItems.length); | ||
} | ||
else { | ||
const activeIndex = this.getActiveIndex(); | ||
return this.itemsParentRef.children.item(activeIndex); | ||
} | ||
} | ||
return undefined; | ||
} | ||
getActiveIndex(items = this.state.filteredItems) { | ||
const { activeItem } = this.state; | ||
if (activeItem == null || isCreateNewItem(activeItem)) { | ||
return -1; | ||
} | ||
// NOTE: this operation is O(n) so it should be avoided in render(). safe for events though. | ||
for (let i = 0; i < items.length; ++i) { | ||
if (executeItemsEqual(this.props.itemsEqual, items[i], activeItem)) { | ||
return i; | ||
} | ||
} | ||
return undefined; | ||
} | ||
getActiveIndex(items = this.state.filteredItems) { | ||
const { activeItem } = this.state; | ||
if (activeItem == null || isCreateNewItem(activeItem)) { | ||
return -1; | ||
} | ||
getItemsParentPadding() { | ||
// assert ref exists because it was checked before calling | ||
const { paddingTop, paddingBottom } = getComputedStyle(this.itemsParentRef); | ||
return { | ||
paddingBottom: pxToNumber(paddingBottom), | ||
paddingTop: pxToNumber(paddingTop), | ||
}; | ||
} | ||
/** | ||
* Get the next enabled item, moving in the given direction from the start | ||
* index. A `null` return value means no suitable item was found. | ||
* @param direction amount to move in each iteration, typically +/-1 | ||
* @param startIndex item to start iteration | ||
*/ | ||
getNextActiveItem(direction, startIndex = this.getActiveIndex()) { | ||
if (this.isCreateItemRendered()) { | ||
const reachedCreate = (startIndex === 0 && direction === -1) || | ||
(startIndex === this.state.filteredItems.length - 1 && direction === 1); | ||
if (reachedCreate) { | ||
return getCreateNewItem(); | ||
} | ||
// NOTE: this operation is O(n) so it should be avoided in render(). safe for events though. | ||
for (let i = 0; i < items.length; ++i) { | ||
if (executeItemsEqual(this.props.itemsEqual, items[i], activeItem)) { | ||
return i; | ||
} | ||
return getFirstEnabledItem(this.state.filteredItems, this.props.itemDisabled, direction, startIndex); | ||
} | ||
isCreateItemRendered() { | ||
return (this.canCreateItems() && | ||
this.state.query !== "" && | ||
// this check is unfortunately O(N) on the number of items, but | ||
// alas, hiding the "Create Item" option when it exactly matches an | ||
// existing item is much clearer. | ||
!this.wouldCreatedItemMatchSomeExistingItem()); | ||
} | ||
canCreateItems() { | ||
return this.props.createNewItemFromQuery != null && this.props.createNewItemRenderer != null; | ||
} | ||
wouldCreatedItemMatchSomeExistingItem() { | ||
// search only the filtered items, not the full items list, because we | ||
// only need to check items that match the current query. | ||
return this.state.filteredItems.some(item => executeItemsEqual(this.props.itemsEqual, item, this.state.createNewItem)); | ||
} | ||
maybeResetQuery() { | ||
if (this.props.resetOnSelect) { | ||
this.setQuery("", true); | ||
return -1; | ||
} | ||
getItemsParentPadding() { | ||
// assert ref exists because it was checked before calling | ||
const { paddingTop, paddingBottom } = getComputedStyle(this.itemsParentRef); | ||
return { | ||
paddingBottom: pxToNumber(paddingBottom), | ||
paddingTop: pxToNumber(paddingTop), | ||
}; | ||
} | ||
/** | ||
* Get the next enabled item, moving in the given direction from the start | ||
* index. A `null` return value means no suitable item was found. | ||
* @param direction amount to move in each iteration, typically +/-1 | ||
* @param startIndex item to start iteration | ||
*/ | ||
getNextActiveItem(direction, startIndex = this.getActiveIndex()) { | ||
if (this.isCreateItemRendered()) { | ||
const reachedCreate = (startIndex === 0 && direction === -1) || | ||
(startIndex === this.state.filteredItems.length - 1 && direction === 1); | ||
if (reachedCreate) { | ||
return getCreateNewItem(); | ||
} | ||
} | ||
return getFirstEnabledItem(this.state.filteredItems, this.props.itemDisabled, direction, startIndex); | ||
} | ||
QueryList.displayName = `${DISPLAYNAME_PREFIX}.QueryList`; | ||
QueryList.defaultProps = { | ||
disabled: false, | ||
resetOnQuery: true, | ||
}; | ||
return QueryList; | ||
})(); | ||
export { QueryList }; | ||
isCreateItemRendered() { | ||
return (this.canCreateItems() && | ||
this.state.query !== "" && | ||
// this check is unfortunately O(N) on the number of items, but | ||
// alas, hiding the "Create Item" option when it exactly matches an | ||
// existing item is much clearer. | ||
!this.wouldCreatedItemMatchSomeExistingItem()); | ||
} | ||
canCreateItems() { | ||
return this.props.createNewItemFromQuery != null && this.props.createNewItemRenderer != null; | ||
} | ||
wouldCreatedItemMatchSomeExistingItem() { | ||
// search only the filtered items, not the full items list, because we | ||
// only need to check items that match the current query. | ||
return this.state.filteredItems.some(item => executeItemsEqual(this.props.itemsEqual, item, this.state.createNewItem)); | ||
} | ||
maybeResetQuery() { | ||
if (this.props.resetOnSelect) { | ||
this.setQuery("", true); | ||
} | ||
} | ||
} | ||
QueryList.displayName = `${DISPLAYNAME_PREFIX}.QueryList`; | ||
QueryList.defaultProps = { | ||
disabled: false, | ||
resetOnQuery: true, | ||
}; | ||
function pxToNumber(value) { | ||
@@ -385,0 +381,0 @@ return value == null ? 0 : parseInt(value.slice(0, -2), 10); |
@@ -20,120 +20,118 @@ /* | ||
import { QueryList } from "../query-list/queryList"; | ||
let MultiSelect = /** @class */ (() => { | ||
class MultiSelect extends React.PureComponent { | ||
constructor() { | ||
super(...arguments); | ||
this.state = { | ||
isOpen: (this.props.popoverProps && this.props.popoverProps.isOpen) || false, | ||
export class MultiSelect extends React.PureComponent { | ||
constructor() { | ||
super(...arguments); | ||
this.state = { | ||
isOpen: (this.props.popoverProps && this.props.popoverProps.isOpen) || false, | ||
}; | ||
this.TypedQueryList = QueryList.ofType(); | ||
this.input = null; | ||
this.queryList = null; | ||
this.refHandlers = { | ||
input: (ref) => { | ||
this.input = ref; | ||
Utils.safeInvokeMember(this.props.tagInputProps, "inputRef", ref); | ||
}, | ||
queryList: (ref) => (this.queryList = ref), | ||
}; | ||
this.renderQueryList = (listProps) => { | ||
const { fill, tagInputProps = {}, popoverProps = {}, selectedItems = [], placeholder } = this.props; | ||
const { handlePaste, handleKeyDown, handleKeyUp } = listProps; | ||
if (fill) { | ||
popoverProps.fill = true; | ||
tagInputProps.fill = true; | ||
} | ||
// add our own inputProps.className so that we can reference it in event handlers | ||
const inputProps = { | ||
...tagInputProps.inputProps, | ||
className: classNames(tagInputProps.inputProps?.className, Classes.MULTISELECT_TAG_INPUT_INPUT), | ||
}; | ||
this.TypedQueryList = QueryList.ofType(); | ||
this.input = null; | ||
this.queryList = null; | ||
this.refHandlers = { | ||
input: (ref) => { | ||
this.input = ref; | ||
Utils.safeInvokeMember(this.props.tagInputProps, "inputRef", ref); | ||
}, | ||
queryList: (ref) => (this.queryList = ref), | ||
const handleTagInputAdd = (values, method) => { | ||
if (method === "paste") { | ||
handlePaste(values); | ||
} | ||
}; | ||
this.renderQueryList = (listProps) => { | ||
const { fill, tagInputProps = {}, popoverProps = {}, selectedItems = [], placeholder } = this.props; | ||
const { handlePaste, handleKeyDown, handleKeyUp } = listProps; | ||
if (fill) { | ||
popoverProps.fill = true; | ||
tagInputProps.fill = true; | ||
} | ||
// add our own inputProps.className so that we can reference it in event handlers | ||
const inputProps = { | ||
...tagInputProps.inputProps, | ||
className: classNames(tagInputProps.inputProps?.className, Classes.MULTISELECT_TAG_INPUT_INPUT), | ||
}; | ||
const handleTagInputAdd = (values, method) => { | ||
if (method === "paste") { | ||
handlePaste(values); | ||
return (React.createElement(Popover, Object.assign({ autoFocus: false, canEscapeKeyClose: true, enforceFocus: false, isOpen: this.state.isOpen, position: Position.BOTTOM_LEFT }, popoverProps, { className: classNames(listProps.className, popoverProps.className), interactionKind: PopoverInteractionKind.CLICK, onInteraction: this.handlePopoverInteraction, popoverClassName: classNames(Classes.MULTISELECT_POPOVER, popoverProps.popoverClassName), onOpened: this.handlePopoverOpened }), | ||
React.createElement("div", { onKeyDown: this.getTagInputKeyDownHandler(handleKeyDown), onKeyUp: this.getTagInputKeyUpHandler(handleKeyUp) }, | ||
React.createElement(TagInput, Object.assign({ placeholder: placeholder }, tagInputProps, { className: classNames(Classes.MULTISELECT, tagInputProps.className), inputRef: this.refHandlers.input, inputProps: inputProps, inputValue: listProps.query, onAdd: handleTagInputAdd, onInputChange: listProps.handleQueryChange, values: selectedItems.map(this.props.tagRenderer) }))), | ||
React.createElement("div", { onKeyDown: handleKeyDown, onKeyUp: handleKeyUp }, listProps.itemList))); | ||
}; | ||
this.handleItemSelect = (item, evt) => { | ||
if (this.input != null) { | ||
this.input.focus(); | ||
} | ||
Utils.safeInvoke(this.props.onItemSelect, item, evt); | ||
}; | ||
this.handleQueryChange = (query, evt) => { | ||
this.setState({ isOpen: query.length > 0 || !this.props.openOnKeyDown }); | ||
Utils.safeInvoke(this.props.onQueryChange, query, evt); | ||
}; | ||
// Popover interaction kind is CLICK, so this only handles click events. | ||
// Note that we defer to the next animation frame in order to get the latest document.activeElement | ||
this.handlePopoverInteraction = (nextOpenState) => requestAnimationFrame(() => { | ||
const isInputFocused = this.input === document.activeElement; | ||
if (this.input != null && !isInputFocused) { | ||
// input is no longer focused, we should close the popover | ||
this.setState({ isOpen: false }); | ||
} | ||
else if (!this.props.openOnKeyDown) { | ||
// we should open immediately on click focus events | ||
this.setState({ isOpen: true }); | ||
} | ||
this.props.popoverProps?.onInteraction?.(nextOpenState); | ||
}); | ||
this.handlePopoverOpened = (node) => { | ||
if (this.queryList != null) { | ||
// scroll active item into view after popover transition completes and all dimensions are stable. | ||
this.queryList.scrollActiveItemIntoView(); | ||
} | ||
Utils.safeInvokeMember(this.props.popoverProps, "onOpened", node); | ||
}; | ||
this.getTagInputKeyDownHandler = (handleQueryListKeyDown) => { | ||
return (e) => { | ||
// HACKHACK: https://github.com/palantir/blueprint/issues/4165 | ||
// eslint-disable-next-line deprecation/deprecation | ||
const { which } = e; | ||
if (which === Keys.ESCAPE || which === Keys.TAB) { | ||
// By default the escape key will not trigger a blur on the | ||
// input element. It must be done explicitly. | ||
if (this.input != null) { | ||
this.input.blur(); | ||
} | ||
}; | ||
return (React.createElement(Popover, Object.assign({ autoFocus: false, canEscapeKeyClose: true, enforceFocus: false, isOpen: this.state.isOpen, position: Position.BOTTOM_LEFT }, popoverProps, { className: classNames(listProps.className, popoverProps.className), interactionKind: PopoverInteractionKind.CLICK, onInteraction: this.handlePopoverInteraction, popoverClassName: classNames(Classes.MULTISELECT_POPOVER, popoverProps.popoverClassName), onOpened: this.handlePopoverOpened }), | ||
React.createElement("div", { onKeyDown: this.getTagInputKeyDownHandler(handleKeyDown), onKeyUp: this.getTagInputKeyUpHandler(handleKeyUp) }, | ||
React.createElement(TagInput, Object.assign({ placeholder: placeholder }, tagInputProps, { className: classNames(Classes.MULTISELECT, tagInputProps.className), inputRef: this.refHandlers.input, inputProps: inputProps, inputValue: listProps.query, onAdd: handleTagInputAdd, onInputChange: listProps.handleQueryChange, values: selectedItems.map(this.props.tagRenderer) }))), | ||
React.createElement("div", { onKeyDown: handleKeyDown, onKeyUp: handleKeyUp }, listProps.itemList))); | ||
}; | ||
this.handleItemSelect = (item, evt) => { | ||
if (this.input != null) { | ||
this.input.focus(); | ||
} | ||
Utils.safeInvoke(this.props.onItemSelect, item, evt); | ||
}; | ||
this.handleQueryChange = (query, evt) => { | ||
this.setState({ isOpen: query.length > 0 || !this.props.openOnKeyDown }); | ||
Utils.safeInvoke(this.props.onQueryChange, query, evt); | ||
}; | ||
// Popover interaction kind is CLICK, so this only handles click events. | ||
// Note that we defer to the next animation frame in order to get the latest document.activeElement | ||
this.handlePopoverInteraction = (nextOpenState) => requestAnimationFrame(() => { | ||
const isInputFocused = this.input === document.activeElement; | ||
if (this.input != null && !isInputFocused) { | ||
// input is no longer focused, we should close the popover | ||
this.setState({ isOpen: false }); | ||
} | ||
else if (!this.props.openOnKeyDown) { | ||
// we should open immediately on click focus events | ||
else if (!(which === Keys.BACKSPACE || which === Keys.ARROW_LEFT || which === Keys.ARROW_RIGHT)) { | ||
this.setState({ isOpen: true }); | ||
} | ||
this.props.popoverProps?.onInteraction?.(nextOpenState); | ||
}); | ||
this.handlePopoverOpened = (node) => { | ||
if (this.queryList != null) { | ||
// scroll active item into view after popover transition completes and all dimensions are stable. | ||
this.queryList.scrollActiveItemIntoView(); | ||
const isTargetingTagRemoveButton = e.target.closest(`.${CoreClasses.TAG_REMOVE}`) != null; | ||
if (this.state.isOpen && !isTargetingTagRemoveButton) { | ||
Utils.safeInvoke(handleQueryListKeyDown, e); | ||
} | ||
Utils.safeInvokeMember(this.props.popoverProps, "onOpened", node); | ||
}; | ||
this.getTagInputKeyDownHandler = (handleQueryListKeyDown) => { | ||
return (e) => { | ||
const { which } = e; | ||
if (which === Keys.ESCAPE || which === Keys.TAB) { | ||
// By default the escape key will not trigger a blur on the | ||
// input element. It must be done explicitly. | ||
if (this.input != null) { | ||
this.input.blur(); | ||
} | ||
this.setState({ isOpen: false }); | ||
} | ||
else if (!(which === Keys.BACKSPACE || which === Keys.ARROW_LEFT || which === Keys.ARROW_RIGHT)) { | ||
this.setState({ isOpen: true }); | ||
} | ||
const isTargetingTagRemoveButton = e.target.closest(`.${CoreClasses.TAG_REMOVE}`) != null; | ||
if (this.state.isOpen && !isTargetingTagRemoveButton) { | ||
Utils.safeInvoke(handleQueryListKeyDown, e); | ||
} | ||
}; | ||
}; | ||
this.getTagInputKeyUpHandler = (handleQueryListKeyUp) => { | ||
return (e) => { | ||
const isTargetingInput = e.target.classList.contains(Classes.MULTISELECT_TAG_INPUT_INPUT); | ||
// only handle events when the focus is on the actual <input> inside the TagInput, as that's | ||
// what QueryList is designed to do | ||
if (this.state.isOpen && isTargetingInput) { | ||
Utils.safeInvoke(handleQueryListKeyUp, e); | ||
} | ||
}; | ||
this.getTagInputKeyUpHandler = (handleQueryListKeyUp) => { | ||
return (e) => { | ||
const isTargetingInput = e.target.classList.contains(Classes.MULTISELECT_TAG_INPUT_INPUT); | ||
// only handle events when the focus is on the actual <input> inside the TagInput, as that's | ||
// what QueryList is designed to do | ||
if (this.state.isOpen && isTargetingInput) { | ||
Utils.safeInvoke(handleQueryListKeyUp, e); | ||
} | ||
}; | ||
}; | ||
} | ||
static ofType() { | ||
return MultiSelect; | ||
} | ||
render() { | ||
// omit props specific to this component, spread the rest. | ||
const { openOnKeyDown, popoverProps, tagInputProps, ...restProps } = this.props; | ||
return (React.createElement(this.TypedQueryList, Object.assign({}, restProps, { onItemSelect: this.handleItemSelect, onQueryChange: this.handleQueryChange, ref: this.refHandlers.queryList, renderer: this.renderQueryList }))); | ||
} | ||
}; | ||
} | ||
MultiSelect.displayName = `${DISPLAYNAME_PREFIX}.MultiSelect`; | ||
MultiSelect.defaultProps = { | ||
fill: false, | ||
placeholder: "Search...", | ||
}; | ||
return MultiSelect; | ||
})(); | ||
export { MultiSelect }; | ||
static ofType() { | ||
return MultiSelect; | ||
} | ||
render() { | ||
// omit props specific to this component, spread the rest. | ||
const { openOnKeyDown, popoverProps, tagInputProps, ...restProps } = this.props; | ||
return (React.createElement(this.TypedQueryList, Object.assign({}, restProps, { onItemSelect: this.handleItemSelect, onQueryChange: this.handleQueryChange, ref: this.refHandlers.queryList, renderer: this.renderQueryList }))); | ||
} | ||
} | ||
MultiSelect.displayName = `${DISPLAYNAME_PREFIX}.MultiSelect`; | ||
MultiSelect.defaultProps = { | ||
fill: false, | ||
placeholder: "Search...", | ||
}; | ||
//# sourceMappingURL=multiSelect.js.map |
@@ -21,101 +21,99 @@ /* | ||
import { QueryList } from "../query-list/queryList"; | ||
let Select = /** @class */ (() => { | ||
class Select extends React.PureComponent { | ||
constructor() { | ||
super(...arguments); | ||
this.state = { isOpen: false }; | ||
this.TypedQueryList = QueryList.ofType(); | ||
this.inputEl = null; | ||
this.queryList = null; | ||
this.refHandlers = { | ||
input: isRefObject(this.props.inputProps?.inputRef) | ||
? (this.inputEl = this.props.inputProps.inputRef) | ||
: (ref) => { | ||
this.inputEl = ref; | ||
this.props.inputProps?.inputRef?.(ref); | ||
}, | ||
queryList: (ref) => (this.queryList = ref), | ||
}; | ||
this.renderQueryList = (listProps) => { | ||
// not using defaultProps cuz they're hard to type with generics (can't use <T> on static members) | ||
const { filterable = true, disabled = false, inputProps = {}, popoverProps = {} } = this.props; | ||
const input = (React.createElement(InputGroup, Object.assign({ leftIcon: "search", placeholder: "Filter...", rightElement: this.maybeRenderClearButton(listProps.query) }, inputProps, { inputRef: this.refHandlers.input, onChange: listProps.handleQueryChange, value: listProps.query }))); | ||
const { handleKeyDown, handleKeyUp } = listProps; | ||
return (React.createElement(Popover, Object.assign({ autoFocus: false, enforceFocus: false, isOpen: this.state.isOpen, disabled: disabled, position: Position.BOTTOM_LEFT }, popoverProps, { className: classNames(listProps.className, popoverProps.className), onInteraction: this.handlePopoverInteraction, popoverClassName: classNames(Classes.SELECT_POPOVER, popoverProps.popoverClassName), onOpening: this.handlePopoverOpening, onOpened: this.handlePopoverOpened, onClosing: this.handlePopoverClosing }), | ||
React.createElement("div", { onKeyDown: this.state.isOpen ? handleKeyDown : this.handleTargetKeyDown, onKeyUp: this.state.isOpen ? handleKeyUp : undefined }, this.props.children), | ||
React.createElement("div", { onKeyDown: handleKeyDown, onKeyUp: handleKeyUp }, | ||
filterable ? input : undefined, | ||
listProps.itemList))); | ||
}; | ||
this.handleTargetKeyDown = (event) => { | ||
// open popover when arrow key pressed on target while closed | ||
if (event.which === Keys.ARROW_UP || event.which === Keys.ARROW_DOWN) { | ||
event.preventDefault(); | ||
this.setState({ isOpen: true }); | ||
export class Select extends React.PureComponent { | ||
constructor() { | ||
super(...arguments); | ||
this.state = { isOpen: false }; | ||
this.TypedQueryList = QueryList.ofType(); | ||
this.inputEl = null; | ||
this.queryList = null; | ||
this.refHandlers = { | ||
input: isRefObject(this.props.inputProps?.inputRef) | ||
? (this.inputEl = this.props.inputProps.inputRef) | ||
: (ref) => { | ||
this.inputEl = ref; | ||
this.props.inputProps?.inputRef?.(ref); | ||
}, | ||
queryList: (ref) => (this.queryList = ref), | ||
}; | ||
this.renderQueryList = (listProps) => { | ||
// not using defaultProps cuz they're hard to type with generics (can't use <T> on static members) | ||
const { filterable = true, disabled = false, inputProps = {}, popoverProps = {} } = this.props; | ||
const input = (React.createElement(InputGroup, Object.assign({ leftIcon: "search", placeholder: "Filter...", rightElement: this.maybeRenderClearButton(listProps.query) }, inputProps, { inputRef: this.refHandlers.input, onChange: listProps.handleQueryChange, value: listProps.query }))); | ||
const { handleKeyDown, handleKeyUp } = listProps; | ||
return (React.createElement(Popover, Object.assign({ autoFocus: false, enforceFocus: false, isOpen: this.state.isOpen, disabled: disabled, position: Position.BOTTOM_LEFT }, popoverProps, { className: classNames(listProps.className, popoverProps.className), onInteraction: this.handlePopoverInteraction, popoverClassName: classNames(Classes.SELECT_POPOVER, popoverProps.popoverClassName), onOpening: this.handlePopoverOpening, onOpened: this.handlePopoverOpened, onClosing: this.handlePopoverClosing }), | ||
React.createElement("div", { onKeyDown: this.state.isOpen ? handleKeyDown : this.handleTargetKeyDown, onKeyUp: this.state.isOpen ? handleKeyUp : undefined }, this.props.children), | ||
React.createElement("div", { onKeyDown: handleKeyDown, onKeyUp: handleKeyUp }, | ||
filterable ? input : undefined, | ||
listProps.itemList))); | ||
}; | ||
this.handleTargetKeyDown = (event) => { | ||
// open popover when arrow key pressed on target while closed | ||
// HACKHACK: https://github.com/palantir/blueprint/issues/4165 | ||
// eslint-disable-next-line deprecation/deprecation | ||
if (event.which === Keys.ARROW_UP || event.which === Keys.ARROW_DOWN) { | ||
event.preventDefault(); | ||
this.setState({ isOpen: true }); | ||
} | ||
}; | ||
this.handleItemSelect = (item, event) => { | ||
this.setState({ isOpen: false }); | ||
Utils.safeInvoke(this.props.onItemSelect, item, event); | ||
}; | ||
this.handlePopoverInteraction = (isOpen) => { | ||
this.setState({ isOpen }); | ||
Utils.safeInvokeMember(this.props.popoverProps, "onInteraction", isOpen); | ||
}; | ||
this.handlePopoverOpening = (node) => { | ||
// save currently focused element before popover steals focus, so we can restore it when closing. | ||
this.previousFocusedElement = document.activeElement; | ||
if (this.props.resetOnClose) { | ||
this.resetQuery(); | ||
} | ||
Utils.safeInvokeMember(this.props.popoverProps, "onOpening", node); | ||
}; | ||
this.handlePopoverOpened = (node) => { | ||
// scroll active item into view after popover transition completes and all dimensions are stable. | ||
if (this.queryList != null) { | ||
this.queryList.scrollActiveItemIntoView(); | ||
} | ||
requestAnimationFrame(() => { | ||
const { inputProps = {} } = this.props; | ||
// autofocus is enabled by default | ||
if (inputProps.autoFocus !== false && this.inputEl != null) { | ||
getRef(this.inputEl).focus(); | ||
} | ||
}; | ||
this.handleItemSelect = (item, event) => { | ||
this.setState({ isOpen: false }); | ||
Utils.safeInvoke(this.props.onItemSelect, item, event); | ||
}; | ||
this.handlePopoverInteraction = (isOpen) => { | ||
this.setState({ isOpen }); | ||
Utils.safeInvokeMember(this.props.popoverProps, "onInteraction", isOpen); | ||
}; | ||
this.handlePopoverOpening = (node) => { | ||
// save currently focused element before popover steals focus, so we can restore it when closing. | ||
this.previousFocusedElement = document.activeElement; | ||
if (this.props.resetOnClose) { | ||
this.resetQuery(); | ||
}); | ||
Utils.safeInvokeMember(this.props.popoverProps, "onOpened", node); | ||
}; | ||
this.handlePopoverClosing = (node) => { | ||
// restore focus to saved element. | ||
// timeout allows popover to begin closing and remove focus handlers beforehand. | ||
requestAnimationFrame(() => { | ||
if (this.previousFocusedElement !== undefined) { | ||
this.previousFocusedElement.focus(); | ||
this.previousFocusedElement = undefined; | ||
} | ||
Utils.safeInvokeMember(this.props.popoverProps, "onOpening", node); | ||
}; | ||
this.handlePopoverOpened = (node) => { | ||
// scroll active item into view after popover transition completes and all dimensions are stable. | ||
if (this.queryList != null) { | ||
this.queryList.scrollActiveItemIntoView(); | ||
} | ||
requestAnimationFrame(() => { | ||
const { inputProps = {} } = this.props; | ||
// autofocus is enabled by default | ||
if (inputProps.autoFocus !== false && this.inputEl != null) { | ||
getRef(this.inputEl).focus(); | ||
} | ||
}); | ||
Utils.safeInvokeMember(this.props.popoverProps, "onOpened", node); | ||
}; | ||
this.handlePopoverClosing = (node) => { | ||
// restore focus to saved element. | ||
// timeout allows popover to begin closing and remove focus handlers beforehand. | ||
requestAnimationFrame(() => { | ||
if (this.previousFocusedElement !== undefined) { | ||
this.previousFocusedElement.focus(); | ||
this.previousFocusedElement = undefined; | ||
} | ||
}); | ||
Utils.safeInvokeMember(this.props.popoverProps, "onClosing", node); | ||
}; | ||
this.resetQuery = () => this.queryList && this.queryList.setQuery("", true); | ||
}); | ||
Utils.safeInvokeMember(this.props.popoverProps, "onClosing", node); | ||
}; | ||
this.resetQuery = () => this.queryList && this.queryList.setQuery("", true); | ||
} | ||
static ofType() { | ||
return Select; | ||
} | ||
render() { | ||
// omit props specific to this component, spread the rest. | ||
const { filterable, inputProps, popoverProps, ...restProps } = this.props; | ||
return (React.createElement(this.TypedQueryList, Object.assign({}, restProps, { onItemSelect: this.handleItemSelect, ref: this.refHandlers.queryList, renderer: this.renderQueryList }))); | ||
} | ||
componentDidUpdate(_prevProps, prevState) { | ||
if (this.state.isOpen && !prevState.isOpen && this.queryList != null) { | ||
this.queryList.scrollActiveItemIntoView(); | ||
} | ||
static ofType() { | ||
return Select; | ||
} | ||
render() { | ||
// omit props specific to this component, spread the rest. | ||
const { filterable, inputProps, popoverProps, ...restProps } = this.props; | ||
return (React.createElement(this.TypedQueryList, Object.assign({}, restProps, { onItemSelect: this.handleItemSelect, ref: this.refHandlers.queryList, renderer: this.renderQueryList }))); | ||
} | ||
componentDidUpdate(_prevProps, prevState) { | ||
if (this.state.isOpen && !prevState.isOpen && this.queryList != null) { | ||
this.queryList.scrollActiveItemIntoView(); | ||
} | ||
} | ||
maybeRenderClearButton(query) { | ||
return query.length > 0 ? React.createElement(Button, { icon: "cross", minimal: true, onClick: this.resetQuery }) : undefined; | ||
} | ||
} | ||
Select.displayName = `${DISPLAYNAME_PREFIX}.Select`; | ||
return Select; | ||
})(); | ||
export { Select }; | ||
maybeRenderClearButton(query) { | ||
return query.length > 0 ? React.createElement(Button, { icon: "cross", minimal: true, onClick: this.resetQuery }) : undefined; | ||
} | ||
} | ||
Select.displayName = `${DISPLAYNAME_PREFIX}.Select`; | ||
//# sourceMappingURL=select.js.map |
@@ -21,196 +21,194 @@ /* | ||
import { QueryList } from "../query-list/queryList"; | ||
let Suggest = /** @class */ (() => { | ||
class Suggest extends React.PureComponent { | ||
constructor() { | ||
super(...arguments); | ||
this.state = { | ||
isOpen: (this.props.popoverProps != null && this.props.popoverProps.isOpen) || false, | ||
selectedItem: this.getInitialSelectedItem(), | ||
}; | ||
this.TypedQueryList = QueryList.ofType(); | ||
this.inputEl = null; | ||
this.queryList = null; | ||
this.refHandlers = { | ||
input: isRefObject(this.props.inputProps?.inputRef) | ||
? (this.inputEl = this.props.inputProps.inputRef) | ||
: (ref) => { | ||
this.inputEl = ref; | ||
this.props.inputProps?.inputRef?.(ref); | ||
}, | ||
queryList: (ref) => (this.queryList = ref), | ||
}; | ||
this.renderQueryList = (listProps) => { | ||
const { fill, inputProps = {}, popoverProps = {} } = this.props; | ||
const { isOpen, selectedItem } = this.state; | ||
const { handleKeyDown, handleKeyUp } = listProps; | ||
const { autoComplete = "off", placeholder = "Search..." } = inputProps; | ||
const selectedItemText = selectedItem ? this.props.inputValueRenderer(selectedItem) : ""; | ||
// placeholder shows selected item while open. | ||
const inputPlaceholder = isOpen && selectedItemText ? selectedItemText : placeholder; | ||
// value shows query when open, and query remains when closed if nothing is selected. | ||
// if resetOnClose is enabled, then hide query when not open. (see handlePopoverOpening) | ||
const inputValue = isOpen | ||
? listProps.query | ||
: selectedItemText || (this.props.resetOnClose ? "" : listProps.query); | ||
if (fill) { | ||
popoverProps.fill = true; | ||
inputProps.fill = true; | ||
export class Suggest extends React.PureComponent { | ||
constructor() { | ||
super(...arguments); | ||
this.state = { | ||
isOpen: (this.props.popoverProps != null && this.props.popoverProps.isOpen) || false, | ||
selectedItem: this.getInitialSelectedItem(), | ||
}; | ||
this.TypedQueryList = QueryList.ofType(); | ||
this.inputEl = null; | ||
this.queryList = null; | ||
this.refHandlers = { | ||
input: isRefObject(this.props.inputProps?.inputRef) | ||
? (this.inputEl = this.props.inputProps.inputRef) | ||
: (ref) => { | ||
this.inputEl = ref; | ||
this.props.inputProps?.inputRef?.(ref); | ||
}, | ||
queryList: (ref) => (this.queryList = ref), | ||
}; | ||
this.renderQueryList = (listProps) => { | ||
const { fill, inputProps = {}, popoverProps = {} } = this.props; | ||
const { isOpen, selectedItem } = this.state; | ||
const { handleKeyDown, handleKeyUp } = listProps; | ||
const { autoComplete = "off", placeholder = "Search..." } = inputProps; | ||
const selectedItemText = selectedItem ? this.props.inputValueRenderer(selectedItem) : ""; | ||
// placeholder shows selected item while open. | ||
const inputPlaceholder = isOpen && selectedItemText ? selectedItemText : placeholder; | ||
// value shows query when open, and query remains when closed if nothing is selected. | ||
// if resetOnClose is enabled, then hide query when not open. (see handlePopoverOpening) | ||
const inputValue = isOpen | ||
? listProps.query | ||
: selectedItemText || (this.props.resetOnClose ? "" : listProps.query); | ||
if (fill) { | ||
popoverProps.fill = true; | ||
inputProps.fill = true; | ||
} | ||
return (React.createElement(Popover, Object.assign({ autoFocus: false, enforceFocus: false, isOpen: isOpen, position: Position.BOTTOM_LEFT }, popoverProps, { className: classNames(listProps.className, popoverProps.className), interactionKind: PopoverInteractionKind.CLICK, onInteraction: this.handlePopoverInteraction, popoverClassName: classNames(Classes.SELECT_POPOVER, popoverProps.popoverClassName), onOpening: this.handlePopoverOpening, onOpened: this.handlePopoverOpened }), | ||
React.createElement(InputGroup, Object.assign({ autoComplete: autoComplete, disabled: this.props.disabled }, inputProps, { inputRef: this.refHandlers.input, onChange: listProps.handleQueryChange, onFocus: this.handleInputFocus, onKeyDown: this.getTargetKeyDownHandler(handleKeyDown), onKeyUp: this.getTargetKeyUpHandler(handleKeyUp), placeholder: inputPlaceholder, value: inputValue })), | ||
React.createElement("div", { onKeyDown: handleKeyDown, onKeyUp: handleKeyUp }, listProps.itemList))); | ||
}; | ||
this.selectText = () => { | ||
// wait until the input is properly focused to select the text inside of it | ||
requestAnimationFrame(() => { | ||
if (this.inputEl != null) { | ||
const input = getRef(this.inputEl); | ||
input.setSelectionRange(0, input.value.length); | ||
} | ||
return (React.createElement(Popover, Object.assign({ autoFocus: false, enforceFocus: false, isOpen: isOpen, position: Position.BOTTOM_LEFT }, popoverProps, { className: classNames(listProps.className, popoverProps.className), interactionKind: PopoverInteractionKind.CLICK, onInteraction: this.handlePopoverInteraction, popoverClassName: classNames(Classes.SELECT_POPOVER, popoverProps.popoverClassName), onOpening: this.handlePopoverOpening, onOpened: this.handlePopoverOpened }), | ||
React.createElement(InputGroup, Object.assign({ autoComplete: autoComplete, disabled: this.props.disabled }, inputProps, { inputRef: this.refHandlers.input, onChange: listProps.handleQueryChange, onFocus: this.handleInputFocus, onKeyDown: this.getTargetKeyDownHandler(handleKeyDown), onKeyUp: this.getTargetKeyUpHandler(handleKeyUp), placeholder: inputPlaceholder, value: inputValue })), | ||
React.createElement("div", { onKeyDown: handleKeyDown, onKeyUp: handleKeyUp }, listProps.itemList))); | ||
}; | ||
this.selectText = () => { | ||
// wait until the input is properly focused to select the text inside of it | ||
requestAnimationFrame(() => { | ||
if (this.inputEl != null) { | ||
const input = getRef(this.inputEl); | ||
input.setSelectionRange(0, input.value.length); | ||
} | ||
}); | ||
}; | ||
this.handleInputFocus = (event) => { | ||
}); | ||
}; | ||
this.handleInputFocus = (event) => { | ||
this.selectText(); | ||
// TODO can we leverage Popover.openOnTargetFocus for this? | ||
if (!this.props.openOnKeyDown) { | ||
this.setState({ isOpen: true }); | ||
} | ||
Utils.safeInvokeMember(this.props.inputProps, "onFocus", event); | ||
}; | ||
this.handleItemSelect = (item, event) => { | ||
let nextOpenState; | ||
if (!this.props.closeOnSelect) { | ||
if (this.inputEl != null) { | ||
getRef(this.inputEl).focus(); | ||
} | ||
this.selectText(); | ||
// TODO can we leverage Popover.openOnTargetFocus for this? | ||
if (!this.props.openOnKeyDown) { | ||
this.setState({ isOpen: true }); | ||
nextOpenState = true; | ||
} | ||
else { | ||
if (this.inputEl != null) { | ||
getRef(this.inputEl).blur(); | ||
} | ||
Utils.safeInvokeMember(this.props.inputProps, "onFocus", event); | ||
}; | ||
this.handleItemSelect = (item, event) => { | ||
let nextOpenState; | ||
if (!this.props.closeOnSelect) { | ||
nextOpenState = false; | ||
} | ||
// the internal state should only change when uncontrolled. | ||
if (this.props.selectedItem === undefined) { | ||
this.setState({ | ||
isOpen: nextOpenState, | ||
selectedItem: item, | ||
}); | ||
} | ||
else { | ||
// otherwise just set the next open state. | ||
this.setState({ isOpen: nextOpenState }); | ||
} | ||
Utils.safeInvoke(this.props.onItemSelect, item, event); | ||
}; | ||
// Popover interaction kind is CLICK, so this only handles click events. | ||
// Note that we defer to the next animation frame in order to get the latest document.activeElement | ||
this.handlePopoverInteraction = (nextOpenState) => requestAnimationFrame(() => { | ||
const isInputFocused = getRef(this.inputEl) === document.activeElement; | ||
if (this.inputEl != null && !isInputFocused) { | ||
// the input is no longer focused, we should close the popover | ||
this.setState({ isOpen: false }); | ||
} | ||
Utils.safeInvokeMember(this.props.popoverProps, "onInteraction", nextOpenState); | ||
}); | ||
this.handlePopoverOpening = (node) => { | ||
// reset query before opening instead of when closing to prevent flash of unfiltered items. | ||
// this is a limitation of the interactions between QueryList state and Popover transitions. | ||
if (this.props.resetOnClose && this.queryList) { | ||
this.queryList.setQuery("", true); | ||
} | ||
Utils.safeInvokeMember(this.props.popoverProps, "onOpening", node); | ||
}; | ||
this.handlePopoverOpened = (node) => { | ||
// scroll active item into view after popover transition completes and all dimensions are stable. | ||
if (this.queryList != null) { | ||
this.queryList.scrollActiveItemIntoView(); | ||
} | ||
Utils.safeInvokeMember(this.props.popoverProps, "onOpened", node); | ||
}; | ||
this.getTargetKeyDownHandler = (handleQueryListKeyDown) => { | ||
return (evt) => { | ||
// HACKHACK: https://github.com/palantir/blueprint/issues/4165 | ||
// eslint-disable-next-line deprecation/deprecation | ||
const { which } = evt; | ||
if (which === Keys.ESCAPE || which === Keys.TAB) { | ||
if (this.inputEl != null) { | ||
getRef(this.inputEl).focus(); | ||
} | ||
this.selectText(); | ||
nextOpenState = true; | ||
} | ||
else { | ||
if (this.inputEl != null) { | ||
getRef(this.inputEl).blur(); | ||
} | ||
nextOpenState = false; | ||
this.setState({ isOpen: false }); | ||
} | ||
// the internal state should only change when uncontrolled. | ||
if (this.props.selectedItem === undefined) { | ||
this.setState({ | ||
isOpen: nextOpenState, | ||
selectedItem: item, | ||
}); | ||
else if (this.props.openOnKeyDown && | ||
which !== Keys.BACKSPACE && | ||
which !== Keys.ARROW_LEFT && | ||
which !== Keys.ARROW_RIGHT) { | ||
this.setState({ isOpen: true }); | ||
} | ||
else { | ||
// otherwise just set the next open state. | ||
this.setState({ isOpen: nextOpenState }); | ||
if (this.state.isOpen) { | ||
Utils.safeInvoke(handleQueryListKeyDown, evt); | ||
} | ||
Utils.safeInvoke(this.props.onItemSelect, item, event); | ||
Utils.safeInvokeMember(this.props.inputProps, "onKeyDown", evt); | ||
}; | ||
// Popover interaction kind is CLICK, so this only handles click events. | ||
// Note that we defer to the next animation frame in order to get the latest document.activeElement | ||
this.handlePopoverInteraction = (nextOpenState) => requestAnimationFrame(() => { | ||
const isInputFocused = getRef(this.inputEl) === document.activeElement; | ||
if (this.inputEl != null && !isInputFocused) { | ||
// the input is no longer focused, we should close the popover | ||
this.setState({ isOpen: false }); | ||
}; | ||
this.getTargetKeyUpHandler = (handleQueryListKeyUp) => { | ||
return (evt) => { | ||
if (this.state.isOpen) { | ||
Utils.safeInvoke(handleQueryListKeyUp, evt); | ||
} | ||
Utils.safeInvokeMember(this.props.popoverProps, "onInteraction", nextOpenState); | ||
}); | ||
this.handlePopoverOpening = (node) => { | ||
// reset query before opening instead of when closing to prevent flash of unfiltered items. | ||
// this is a limitation of the interactions between QueryList state and Popover transitions. | ||
if (this.props.resetOnClose && this.queryList) { | ||
this.queryList.setQuery("", true); | ||
} | ||
Utils.safeInvokeMember(this.props.popoverProps, "onOpening", node); | ||
Utils.safeInvokeMember(this.props.inputProps, "onKeyUp", evt); | ||
}; | ||
this.handlePopoverOpened = (node) => { | ||
// scroll active item into view after popover transition completes and all dimensions are stable. | ||
if (this.queryList != null) { | ||
this.queryList.scrollActiveItemIntoView(); | ||
} | ||
Utils.safeInvokeMember(this.props.popoverProps, "onOpened", node); | ||
}; | ||
this.getTargetKeyDownHandler = (handleQueryListKeyDown) => { | ||
return (evt) => { | ||
const { which } = evt; | ||
if (which === Keys.ESCAPE || which === Keys.TAB) { | ||
if (this.inputEl != null) { | ||
getRef(this.inputEl).blur(); | ||
} | ||
this.setState({ isOpen: false }); | ||
} | ||
else if (this.props.openOnKeyDown && | ||
which !== Keys.BACKSPACE && | ||
which !== Keys.ARROW_LEFT && | ||
which !== Keys.ARROW_RIGHT) { | ||
this.setState({ isOpen: true }); | ||
} | ||
if (this.state.isOpen) { | ||
Utils.safeInvoke(handleQueryListKeyDown, evt); | ||
} | ||
Utils.safeInvokeMember(this.props.inputProps, "onKeyDown", evt); | ||
}; | ||
}; | ||
this.getTargetKeyUpHandler = (handleQueryListKeyUp) => { | ||
return (evt) => { | ||
if (this.state.isOpen) { | ||
Utils.safeInvoke(handleQueryListKeyUp, evt); | ||
} | ||
Utils.safeInvokeMember(this.props.inputProps, "onKeyUp", evt); | ||
}; | ||
}; | ||
}; | ||
} | ||
static ofType() { | ||
return Suggest; | ||
} | ||
render() { | ||
// omit props specific to this component, spread the rest. | ||
const { disabled, inputProps, popoverProps, ...restProps } = this.props; | ||
return (React.createElement(this.TypedQueryList, Object.assign({}, restProps, { initialActiveItem: this.props.selectedItem ?? undefined, onItemSelect: this.handleItemSelect, ref: this.refHandlers.queryList, renderer: this.renderQueryList }))); | ||
} | ||
componentDidUpdate(_prevProps, prevState) { | ||
// If the selected item prop changes, update the underlying state. | ||
if (this.props.selectedItem !== undefined && this.props.selectedItem !== this.state.selectedItem) { | ||
this.setState({ selectedItem: this.props.selectedItem }); | ||
} | ||
static ofType() { | ||
return Suggest; | ||
if (this.state.isOpen === false && prevState.isOpen === true) { | ||
// just closed, likely by keyboard interaction | ||
// wait until the transition ends so there isn't a flash of content in the popover | ||
setTimeout(() => { | ||
this.maybeResetActiveItemToSelectedItem(); | ||
}, this.props.popoverProps?.transitionDuration ?? Popover.defaultProps.transitionDuration); | ||
} | ||
render() { | ||
// omit props specific to this component, spread the rest. | ||
const { disabled, inputProps, popoverProps, ...restProps } = this.props; | ||
return (React.createElement(this.TypedQueryList, Object.assign({}, restProps, { initialActiveItem: this.props.selectedItem ?? undefined, onItemSelect: this.handleItemSelect, ref: this.refHandlers.queryList, renderer: this.renderQueryList }))); | ||
if (this.state.isOpen && !prevState.isOpen && this.queryList != null) { | ||
this.queryList.scrollActiveItemIntoView(); | ||
} | ||
componentDidUpdate(_prevProps, prevState) { | ||
// If the selected item prop changes, update the underlying state. | ||
if (this.props.selectedItem !== undefined && this.props.selectedItem !== this.state.selectedItem) { | ||
this.setState({ selectedItem: this.props.selectedItem }); | ||
} | ||
if (this.state.isOpen === false && prevState.isOpen === true) { | ||
// just closed, likely by keyboard interaction | ||
// wait until the transition ends so there isn't a flash of content in the popover | ||
setTimeout(() => { | ||
this.maybeResetActiveItemToSelectedItem(); | ||
}, this.props.popoverProps?.transitionDuration ?? Popover.defaultProps.transitionDuration); | ||
} | ||
if (this.state.isOpen && !prevState.isOpen && this.queryList != null) { | ||
this.queryList.scrollActiveItemIntoView(); | ||
} | ||
} | ||
getInitialSelectedItem() { | ||
// controlled > uncontrolled > default | ||
if (this.props.selectedItem !== undefined) { | ||
return this.props.selectedItem; | ||
} | ||
getInitialSelectedItem() { | ||
// controlled > uncontrolled > default | ||
if (this.props.selectedItem !== undefined) { | ||
return this.props.selectedItem; | ||
} | ||
else if (this.props.defaultSelectedItem !== undefined) { | ||
return this.props.defaultSelectedItem; | ||
} | ||
else { | ||
return null; | ||
} | ||
else if (this.props.defaultSelectedItem !== undefined) { | ||
return this.props.defaultSelectedItem; | ||
} | ||
maybeResetActiveItemToSelectedItem() { | ||
const shouldResetActiveItemToSelectedItem = this.props.activeItem === undefined && this.state.selectedItem !== null && !this.props.resetOnSelect; | ||
if (this.queryList !== null && shouldResetActiveItemToSelectedItem) { | ||
this.queryList.setActiveItem(this.props.selectedItem ?? this.state.selectedItem); | ||
} | ||
else { | ||
return null; | ||
} | ||
} | ||
Suggest.displayName = `${DISPLAYNAME_PREFIX}.Suggest`; | ||
Suggest.defaultProps = { | ||
closeOnSelect: true, | ||
fill: false, | ||
openOnKeyDown: false, | ||
resetOnClose: false, | ||
}; | ||
return Suggest; | ||
})(); | ||
export { Suggest }; | ||
maybeResetActiveItemToSelectedItem() { | ||
const shouldResetActiveItemToSelectedItem = this.props.activeItem === undefined && this.state.selectedItem !== null && !this.props.resetOnSelect; | ||
if (this.queryList !== null && shouldResetActiveItemToSelectedItem) { | ||
this.queryList.setActiveItem(this.props.selectedItem ?? this.state.selectedItem); | ||
} | ||
} | ||
} | ||
Suggest.displayName = `${DISPLAYNAME_PREFIX}.Suggest`; | ||
Suggest.defaultProps = { | ||
closeOnSelect: true, | ||
fill: false, | ||
openOnKeyDown: false, | ||
resetOnClose: false, | ||
}; | ||
//# sourceMappingURL=suggest.js.map |
{ | ||
"name": "@blueprintjs/select", | ||
"version": "3.13.6", | ||
"version": "3.13.7", | ||
"description": "Components related to selecting items from a list", | ||
@@ -38,5 +38,5 @@ "main": "lib/cjs/index.js", | ||
"dependencies": { | ||
"@blueprintjs/core": "^3.30.1", | ||
"@blueprintjs/core": "^3.31.0", | ||
"classnames": "^2.2", | ||
"tslib": "~1.10.0" | ||
"tslib": "~1.13.0" | ||
}, | ||
@@ -48,13 +48,13 @@ "peerDependencies": { | ||
"devDependencies": { | ||
"@blueprintjs/karma-build-scripts": "^1.0.1", | ||
"@blueprintjs/node-build-scripts": "^1.3.2", | ||
"@blueprintjs/karma-build-scripts": "^1.0.2", | ||
"@blueprintjs/node-build-scripts": "^1.3.3", | ||
"enzyme": "^3.11.0", | ||
"karma": "^5.0.9", | ||
"mocha": "^7.2.0", | ||
"karma": "^5.1.1", | ||
"mocha": "^8.1.1", | ||
"npm-run-all": "^4.1.5", | ||
"react": "^16.8.6", | ||
"react-dom": "^16.8.6", | ||
"react-test-renderer": "^16.8.6", | ||
"typescript": "~3.9.3", | ||
"webpack-cli": "^3.3.11" | ||
"react": "^16.13.1", | ||
"react-dom": "^16.13.1", | ||
"react-test-renderer": "^16.13.1", | ||
"typescript": "~3.9.7", | ||
"webpack-cli": "^3.3.12" | ||
}, | ||
@@ -61,0 +61,0 @@ "repository": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
7807
539137
+ Addedtslib@1.13.0(transitive)
- Removedtslib@1.10.0(transitive)
Updated@blueprintjs/core@^3.31.0
Updatedtslib@~1.13.0