diff --git a/package.json b/package.json
index 6647eefa60e..6d92558a388 100644
--- a/package.json
+++ b/package.json
@@ -52,7 +52,6 @@
"@types/numeral": "^0.0.25",
"@types/react-beautiful-dnd": "^12.1.2",
"@types/react-input-autosize": "^2.0.2",
- "@types/react-virtualized": "^9.18.7",
"@types/react-virtualized-auto-sizer": "^1.0.0",
"@types/react-window": "^1.8.1",
"chroma-js": "^2.0.4",
@@ -68,7 +67,6 @@
"react-focus-lock": "^1.17.7",
"react-input-autosize": "^2.2.2",
"react-is": "~16.3.0",
- "react-virtualized": "^9.21.2",
"react-virtualized-auto-sizer": "^1.0.2",
"react-window": "^1.8.5",
"resize-observer-polyfill": "^1.5.0",
diff --git a/src-docs/src/views/combo_box/combo_box_example.js b/src-docs/src/views/combo_box/combo_box_example.js
index 2d2fb9fe41f..19e0a1756a5 100644
--- a/src-docs/src/views/combo_box/combo_box_example.js
+++ b/src-docs/src/views/combo_box/combo_box_example.js
@@ -147,8 +147,8 @@ export const ComboBoxExample = {
text: (
EuiComboBoxList uses{' '}
-
- react-virtualized
+
+ react-window
{' '}
to only render visible options to be super fast no matter how many
options there are.
diff --git a/src/components/combo_box/__snapshots__/combo_box.test.tsx.snap b/src/components/combo_box/__snapshots__/combo_box.test.tsx.snap
index 6d6cedcf6f5..458d4780f91 100644
--- a/src/components/combo_box/__snapshots__/combo_box.test.tsx.snap
+++ b/src/components/combo_box/__snapshots__/combo_box.test.tsx.snap
@@ -316,14 +316,224 @@ exports[`props options list is rendered 1`] = `
class="euiComboBoxOptionsList__rowWrap"
>
+ style="position: relative; height: 189px; width: 0px; overflow: auto; direction: ltr;"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/combo_box/combo_box.tsx b/src/components/combo_box/combo_box.tsx
index ebad2f90cd5..0c368746020 100644
--- a/src/components/combo_box/combo_box.tsx
+++ b/src/components/combo_box/combo_box.tsx
@@ -534,6 +534,7 @@ export class EuiComboBox extends Component<
relatedTarget &&
this.comboBoxRefInstance &&
this.comboBoxRefInstance.contains(relatedTarget);
+
if (!focusedInOptionsList && !focusedInInput) {
this.closeList();
@@ -652,6 +653,10 @@ export class EuiComboBox extends Component<
if (singleSelection) {
requestAnimationFrame(this.closeList);
+ } else {
+ this.setState({
+ activeOptionIndex: this.state.matchingOptions.indexOf(addedOption),
+ });
}
};
diff --git a/src/components/combo_box/combo_box_options_list/combo_box_options_list.tsx b/src/components/combo_box/combo_box_options_list/combo_box_options_list.tsx
index 8d230a1e82b..e6d278914cb 100644
--- a/src/components/combo_box/combo_box_options_list/combo_box_options_list.tsx
+++ b/src/components/combo_box/combo_box_options_list/combo_box_options_list.tsx
@@ -5,7 +5,11 @@ import React, {
RefCallback,
} from 'react';
import classNames from 'classnames';
-import { List, ListProps } from 'react-virtualized'; // eslint-disable-line import/named
+import {
+ FixedSizeList,
+ ListProps,
+ ListChildComponentProps,
+} from 'react-window';
import { EuiCode } from '../../../components/code';
import { EuiFlexGroup, EuiFlexItem } from '../../flex';
@@ -83,6 +87,8 @@ export class EuiComboBoxOptionsList extends Component<
EuiComboBoxOptionsListProps
> {
listRefInstance: RefInstance = null;
+ listRef: FixedSizeList | null = null;
+ listBoxRef: HTMLUListElement | null = null;
static defaultProps = {
'data-test-subj': '',
@@ -126,6 +132,10 @@ export class EuiComboBoxOptionsList extends Component<
) {
this.updatePosition();
}
+
+ if (this.listRef && typeof this.props.activeOptionIndex !== 'undefined') {
+ this.listRef.scrollToItem(this.props.activeOptionIndex, 'auto');
+ }
}
componentWillUnmount() {
@@ -153,6 +163,80 @@ export class EuiComboBoxOptionsList extends Component<
this.listRefInstance = ref;
};
+ setListRef = (ref: FixedSizeList | null) => {
+ this.listRef = ref;
+ };
+
+ setListBoxRef = (ref: HTMLUListElement | null) => {
+ this.listBoxRef = ref;
+
+ if (ref) {
+ ref.setAttribute('id', this.props.rootId('listbox'));
+ ref.setAttribute('role', 'listBox');
+ ref.setAttribute('tabIndex', '0');
+ }
+ };
+
+ ListRow = ({ data, index, style }: ListChildComponentProps) => {
+ const option = data[index];
+ const { isGroupLabelOption, label, value, ...rest } = option;
+ const {
+ singleSelection,
+ selectedOptions,
+ onOptionClick,
+ optionRef,
+ activeOptionIndex,
+ renderOption,
+ searchValue,
+ rootId,
+ } = this.props;
+
+ if (isGroupLabelOption) {
+ return (
+
+ {label}
+
+ );
+ }
+
+ let checked: FilterChecked | undefined = undefined;
+ if (
+ singleSelection &&
+ selectedOptions.length &&
+ selectedOptions[0].label === label
+ ) {
+ checked = 'on';
+ }
+
+ return (
+ {
+ if (onOptionClick) {
+ onOptionClick(option);
+ }
+ }}
+ ref={optionRef.bind(this, index)}
+ isFocused={activeOptionIndex === index}
+ checked={checked}
+ showIcons={singleSelection ? true : false}
+ id={rootId(`_option-${index}`)}
+ title={label}
+ {...rest}>
+ {renderOption ? (
+ renderOption(option, searchValue, OPTION_CONTENT_CLASSNAME)
+ ) : (
+
+ {label}
+
+ )}
+
+ );
+ };
+
render() {
const {
'data-test-subj': dataTestSubj,
@@ -289,65 +373,17 @@ export class EuiComboBoxOptionsList extends Component<
const height = numVisibleOptions * rowHeight;
const optionsList = (
- {
- const option = matchingOptions[index];
- const { isGroupLabelOption, label, value, ...rest } = option;
-
- if (isGroupLabelOption) {
- return (
-
- {label}
-
- );
- }
-
- let checked: FilterChecked | undefined = undefined;
- if (
- singleSelection &&
- selectedOptions.length &&
- selectedOptions[0].label === label
- ) {
- checked = 'on';
- }
-
- return (
- {
- if (onOptionClick) {
- onOptionClick(option);
- }
- }}
- ref={optionRef.bind(this, index)}
- isFocused={activeOptionIndex === index}
- checked={checked}
- showIcons={singleSelection ? true : false}
- id={rootId(`_option-${index}`)}
- title={label}
- {...rest}>
- {renderOption ? (
- renderOption(option, searchValue, OPTION_CONTENT_CLASSNAME)
- ) : (
-
- {label}
-
- )}
-
- );
- }}
- role="listbox"
- rowCount={matchingOptions.length}
- rowHeight={rowHeight}
- scrollToIndex={scrollToIndex}
- width={width}
- />
+ itemCount={matchingOptions.length}
+ itemSize={rowHeight}
+ itemData={matchingOptions}
+ ref={this.setListRef}
+ innerRef={this.setListBoxRef}
+ width={width}>
+ {this.ListRow}
+
);
const classes = classNames(
diff --git a/yarn.lock b/yarn.lock
index c4aadbabcb7..f2ccf20c97e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1303,14 +1303,6 @@
dependencies:
"@types/react" "*"
-"@types/react-virtualized@^9.18.7":
- version "9.21.8"
- resolved "https://registry.yarnpkg.com/@types/react-virtualized/-/react-virtualized-9.21.8.tgz#dc0150a75fd6e42f33729886463ece04d03367ea"
- integrity sha512-7fZoA0Azd2jLIE9XC37fMZgMqaJe3o3pfzGjvrzphoKjBCdT4oNl6wikvo4dDMESDnpkZ8DvVTc7aSe4DW86Ew==
- dependencies:
- "@types/prop-types" "*"
- "@types/react" "*"
-
"@types/react-window@^1.8.1":
version "1.8.1"
resolved "https://registry.yarnpkg.com/@types/react-window/-/react-window-1.8.1.tgz#6e1ceab2e6f2f78dbf1f774ee0e00f1bb0364bb3"
@@ -3358,11 +3350,6 @@ cloneable-readable@^1.0.0:
process-nextick-args "^1.0.6"
through2 "^2.0.1"
-clsx@^1.0.1:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.0.tgz#62937c6adfea771247c34b54d320fb99624f5702"
- integrity sha512-3avwM37fSK5oP6M5rQ9CNe99lwxhXDOeSWVPAOYF6OazUTgZCMb0yWlJpmdD74REy1gkEaFiub2ULv4fq9GUhA==
-
co@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
@@ -4210,7 +4197,7 @@ cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
dependencies:
cssom "0.3.x"
-csstype@^2.2.0, csstype@^2.6.7:
+csstype@^2.2.0:
version "2.6.9"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.9.tgz#05141d0cd557a56b8891394c1911c40c8a98d098"
integrity sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q==
@@ -4672,14 +4659,6 @@ dom-converter@~0.1:
dependencies:
utila "~0.3"
-dom-helpers@^5.0.0:
- version "5.1.3"
- resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.1.3.tgz#7233248eb3a2d1f74aafca31e52c5299cc8ce821"
- integrity sha512-nZD1OtwfWGRBWlpANxacBEZrEuLa16o1nh7YopFWeoF68Zt8GGEmzHu6Xv4F3XaFIC+YXtTLrzgqKxFgLEe4jw==
- dependencies:
- "@babel/runtime" "^7.6.3"
- csstype "^2.6.7"
-
dom-serializer@0, dom-serializer@^0.1.0, dom-serializer@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
@@ -9137,7 +9116,7 @@ loglevel@^1.4.1:
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa"
integrity sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=
-loose-envify@^1.0.0, loose-envify@^1.3.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
+loose-envify@^1.0.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@@ -12208,7 +12187,7 @@ react-konva@16.10.1-0:
react-reconciler "^0.22.1"
scheduler "^0.16.1"
-react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.4:
+react-lifecycles-compat@^3.0.0:
version "3.0.4"
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
@@ -12310,18 +12289,6 @@ react-virtualized-auto-sizer@^1.0.2:
resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.2.tgz#a61dd4f756458bbf63bd895a92379f9b70f803bd"
integrity sha512-MYXhTY1BZpdJFjUovvYHVBmkq79szK/k7V3MO+36gJkWGkrXKtyr4vCPtpphaTLRAdDNoYEYFZWE8LjN+PIHNg==
-react-virtualized@^9.21.2:
- version "9.21.2"
- resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.21.2.tgz#02e6df65c1e020c8dbf574ec4ce971652afca84e"
- integrity sha512-oX7I7KYiUM7lVXQzmhtF4Xg/4UA5duSA+/ZcAvdWlTLFCoFYq1SbauJT5gZK9cZS/wdYR6TPGpX/dqzvTqQeBA==
- dependencies:
- babel-runtime "^6.26.0"
- clsx "^1.0.1"
- dom-helpers "^5.0.0"
- loose-envify "^1.3.0"
- prop-types "^15.6.0"
- react-lifecycles-compat "^3.0.4"
-
react-window@^1.8.5:
version "1.8.5"
resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.5.tgz#a56b39307e79979721021f5d06a67742ecca52d1"