diff --git a/packages/web/src/components/list/MultiList.d.ts b/packages/web/src/components/list/MultiList.d.ts index 8f2008678..82efa9c5f 100644 --- a/packages/web/src/components/list/MultiList.d.ts +++ b/packages/web/src/components/list/MultiList.d.ts @@ -42,6 +42,8 @@ export interface MultiList extends CommonProps { index?: string; preferencesPath?: string; endpoint?: types.endpointConfig; + collapse?: boolean; + defaultCollapse?: boolean; } declare const MultiList: React.ComponentClass; diff --git a/packages/web/src/components/list/MultiList.js b/packages/web/src/components/list/MultiList.js index 9a933ddbb..bda1fcfc3 100644 --- a/packages/web/src/components/list/MultiList.js +++ b/packages/web/src/components/list/MultiList.js @@ -54,6 +54,7 @@ class MultiList extends Component { ? this.getOptions(props.options[props.dataField].buckets, props) : []; + const defaultCollapse = props.defaultCollapse !== undefined ? props.defaultCollapse : true; this.state = { currentValue, options, @@ -61,6 +62,7 @@ class MultiList extends Component { after: {}, // for composite aggs, prevAfter: {}, // useful when we want to prevent the showLoadMore results isLastBucket: false, + isOpen: props.collapse ? !defaultCollapse : true, }; this.internalComponent = getInternalComponentID(props.componentId); @@ -459,6 +461,87 @@ class MultiList extends Component { return getComponent(data, this.props); } + toggleCollapse = () => { + this.setState(state => ({ + isOpen: !state.isOpen, + })); + }; + + handleCollapseKeyPress = (e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + this.toggleCollapse(); + } + }; + + renderTitle() { + const { title, renderTitle, showItemCount, innerClass, collapse } = this.props; + const { isOpen } = this.state; + const itemsCount = this.listItems ? this.listItems.length : 0; + + if (renderTitle) { + return isFunction(renderTitle) + ? renderTitle(itemsCount, this.listItems) + : renderTitle; + } + + if (title) { + const titleContent = ( + + {title} + {showItemCount && ( + + {itemsCount} + + )} + {collapse && ( + + {isOpen ? '▼' : '▲'} + + )} + + ); + + if (collapse) { + return ( + + {titleContent} + + ); + } + + return ( + + {titleContent} + + ); + } + return null; + } + render() { const { selectAllLabel, @@ -490,116 +573,116 @@ class MultiList extends Component { const isAllChecked = selectAllLabel ? !!this.state.currentValue[selectAllLabel] : false; return ( - {this.props.title && ( - - {this.props.title} - - )} - {this.renderSearch()} - {this.hasCustomRenderer ? ( - this.getComponent() - ) : ( - + )} ); @@ -661,6 +744,8 @@ MultiList.propTypes = { loadMoreLabel: types.title, index: types.string, endpoint: types.endpoint, + collapse: types.bool, + defaultCollapse: types.bool, }; MultiList.defaultProps = { @@ -678,6 +763,8 @@ MultiList.defaultProps = { missingLabel: 'N/A', showLoadMore: false, loadMoreLabel: 'Load More', + collapse: false, + defaultCollapse: true, }; // Add componentType for SSR diff --git a/packages/web/src/components/list/SingleList.d.ts b/packages/web/src/components/list/SingleList.d.ts index cc443dea3..0c00e9967 100644 --- a/packages/web/src/components/list/SingleList.d.ts +++ b/packages/web/src/components/list/SingleList.d.ts @@ -42,6 +42,8 @@ export interface SingleList extends CommonProps { preferencesPath?: string; enableStrictSelection?: boolean; endpoint?: types.endpointConfig; + collapse?: boolean; + defaultCollapse?: boolean; } declare const SingleList: React.ComponentClass; diff --git a/packages/web/src/components/list/SingleList.js b/packages/web/src/components/list/SingleList.js index 6ad88fd8c..6109064ec 100644 --- a/packages/web/src/components/list/SingleList.js +++ b/packages/web/src/components/list/SingleList.js @@ -45,6 +45,7 @@ class SingleList extends Component { const defaultValue = props.defaultValue || props.value; const currentValue = props.selectedValue || defaultValue; + const defaultCollapse = props.defaultCollapse !== undefined ? props.defaultCollapse : true; this.state = { currentValue: currentValue || '', options: @@ -55,6 +56,7 @@ class SingleList extends Component { after: {}, // for composite aggs, prevAfter: {}, // useful when we want to prevent the showLoadMore results isLastBucket: false, + isOpen: props.collapse ? !defaultCollapse : true, }; this.internalComponent = getInternalComponentID(props.componentId); @@ -354,6 +356,87 @@ class SingleList extends Component { return getComponent(data, this.props); } + toggleCollapse = () => { + this.setState(state => ({ + isOpen: !state.isOpen, + })); + }; + + handleCollapseKeyPress = (e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + this.toggleCollapse(); + } + }; + + renderTitle() { + const { title, renderTitle, showItemCount, innerClass, collapse } = this.props; + const { isOpen } = this.state; + const itemsCount = this.listItems ? this.listItems.length : 0; + + if (renderTitle) { + return isFunction(renderTitle) + ? renderTitle(itemsCount, this.listItems) + : renderTitle; + } + + if (title) { + const titleContent = ( + + {title} + {showItemCount && ( + + {itemsCount} + + )} + {collapse && ( + + {isOpen ? '▼' : '▲'} + + )} + + ); + + if (collapse) { + return ( + + {titleContent} + + ); + } + + return ( + + {titleContent} + + ); + } + return null; + } + render() { const { selectAllLabel, @@ -387,110 +470,110 @@ class SingleList extends Component { return ( - {this.props.title && ( - - {this.props.title} - - )} - {this.renderSearch()} - {this.hasCustomRenderer ? ( - this.getComponent() - ) : ( -
    - {selectAllLabel ? ( -
  • + {this.renderSearch()} + {this.hasCustomRenderer ? ( + this.getComponent() + ) : ( +
      - - - - ) : null} - {this.listItems.length - ? this.listItems.map((item) => { - const isChecked = this.state.currentValue === String(item.key); - return ( -
    • + {selectAllLabel ? ( +
    • - ); - }) // prettier-ignore - : this.props.renderNoResults && this.props.renderNoResults()} - {showLoadMore && !isLastBucket && ( -
      - -
      + ) : null} + {this.listItems.length + ? this.listItems.map((item) => { + const isChecked = this.state.currentValue === String(item.key); + return ( +
    • + + +
    • + ); + }) // prettier-ignore + : this.props.renderNoResults && this.props.renderNoResults()} + {showLoadMore && !isLastBucket && ( +
      + +
      + )} +
    )} -
+ )}
); @@ -552,6 +635,8 @@ SingleList.propTypes = { index: types.string, enableStrictSelection: types.bool, endpoint: types.endpoint, + collapse: types.bool, + defaultCollapse: types.bool, }; SingleList.defaultProps = { @@ -570,6 +655,8 @@ SingleList.defaultProps = { showLoadMore: false, loadMoreLabel: 'Load More', enableStrictSelection: false, + collapse: false, + defaultCollapse: true, }; // Add componentType for SSR