From 0516a10e5ac9eb757ec15bf3aa191065170e5628 Mon Sep 17 00:00:00 2001 From: chriddyp Date: Fri, 28 Jul 2017 19:25:45 -0400 Subject: [PATCH] make dropdowns more performant attempt to fix https://github.com/plotly/dash/issues/103 --- .../dash_core_components/__init__.py | 6 +- .../react-virtualized-select@3.1.0.css | 22 ++++ .../react-virtualized@9.9.0.css | 107 ++++++++++++++++++ packages/dash-core-components/package.json | 4 +- .../src/components/Dropdown.react.js | 14 ++- 5 files changed, 149 insertions(+), 4 deletions(-) create mode 100644 packages/dash-core-components/dash_core_components/react-virtualized-select@3.1.0.css create mode 100644 packages/dash-core-components/dash_core_components/react-virtualized@9.9.0.css diff --git a/packages/dash-core-components/dash_core_components/__init__.py b/packages/dash-core-components/dash_core_components/__init__.py index 79079a2731..84532300d5 100644 --- a/packages/dash-core-components/dash_core_components/__init__.py +++ b/packages/dash-core-components/dash_core_components/__init__.py @@ -31,11 +31,15 @@ _css_dist = [ { "relative_package_path": [ + "rc-slider@6.1.2.css", "react-select@1.0.0-rc.3.min.css", - "rc-slider@6.1.2.css" + "react-virtualized@9.9.0/styles.css", + "react-virtualized-select@3.1.0/styles.css" ], "external_url": [ "https://unpkg.com/react-select@1.0.0-rc.3/dist/react-select.min.css", + "https://unpkg.com/react-virtualized@9.9.0/styles.css", + "https://unpkg.com/react-virtualized-select@3.1.0/styles.css", "https://unpkg.com/rc-slider@6.1.2/assets/index.css" ], "namespace": "dash_core_components" diff --git a/packages/dash-core-components/dash_core_components/react-virtualized-select@3.1.0.css b/packages/dash-core-components/dash_core_components/react-virtualized-select@3.1.0.css new file mode 100644 index 0000000000..ba437b9427 --- /dev/null +++ b/packages/dash-core-components/dash_core_components/react-virtualized-select@3.1.0.css @@ -0,0 +1,22 @@ +.VirtualSelectGrid { + z-index: 1; +} + +.VirtualizedSelectOption { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + padding: 0 .5rem; +} +.VirtualizedSelectFocusedOption { + background-color: rgba(0, 126, 255, 0.1); +} +.VirtualizedSelectDisabledOption { + opacity: 0.5; +} +.VirtualizedSelectSelectedOption { + font-weight: bold; +} diff --git a/packages/dash-core-components/dash_core_components/react-virtualized@9.9.0.css b/packages/dash-core-components/dash_core_components/react-virtualized@9.9.0.css new file mode 100644 index 0000000000..327361089e --- /dev/null +++ b/packages/dash-core-components/dash_core_components/react-virtualized@9.9.0.css @@ -0,0 +1,107 @@ +/* Collection default theme */ + +.ReactVirtualized__Collection { +} + +.ReactVirtualized__Collection__innerScrollContainer { +} + +/* Grid default theme */ + +.ReactVirtualized__Grid { +} + +.ReactVirtualized__Grid__innerScrollContainer { +} + +/* Table default theme */ + +.ReactVirtualized__Table { +} + +.ReactVirtualized__Table__Grid { +} + +.ReactVirtualized__Table__headerRow { + font-weight: 700; + text-transform: uppercase; + display: -webkit-flex; + display: -moz-box; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -moz-box-orient: horizontal; + -moz-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + -webkit-align-items: center; + -moz-box-align: center; + -ms-flex-align: center; + align-items: center; +} +.ReactVirtualized__Table__row { + display: -webkit-flex; + display: -moz-box; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -moz-box-orient: horizontal; + -moz-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + -webkit-align-items: center; + -moz-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.ReactVirtualized__Table__headerTruncatedText { + display: inline-block; + max-width: 100%; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} + +.ReactVirtualized__Table__headerColumn, +.ReactVirtualized__Table__rowColumn { + margin-right: 10px; + min-width: 0px; +} +.ReactVirtualized__Table__rowColumn { + text-overflow: ellipsis; + white-space: nowrap; +} + +.ReactVirtualized__Table__headerColumn:first-of-type, +.ReactVirtualized__Table__rowColumn:first-of-type { + margin-left: 10px; +} +.ReactVirtualized__Table__sortableHeaderColumn { + cursor: pointer; +} + +.ReactVirtualized__Table__sortableHeaderIconContainer { + display: -webkit-flex; + display: -moz-box; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -moz-box-align: center; + -ms-flex-align: center; + align-items: center; +} +.ReactVirtualized__Table__sortableHeaderIcon { + -webkit-flex: 0 0 24px; + -moz-box-flex: 0; + -ms-flex: 0 0 24px; + flex: 0 0 24px; + height: 1em; + width: 1em; + fill: currentColor; +} + +/* List default theme */ + +.ReactVirtualized__List { +} diff --git a/packages/dash-core-components/package.json b/packages/dash-core-components/package.json index 4d78ef65cb..dcf4f01151 100644 --- a/packages/dash-core-components/package.json +++ b/packages/dash-core-components/package.json @@ -34,7 +34,9 @@ "react-dom": "^15.4.0", "react-markdown": "^2.4.5", "react-select": "^1.0.0-rc.3", - "react-syntax-highlighter": "^5.0.0" + "react-select-fast-filter-options": "^0.2.2", + "react-syntax-highlighter": "^5.0.0", + "react-virtualized-select": "^3.1.0" }, "devDependencies": { "component-playground": "^1.3.2", diff --git a/packages/dash-core-components/src/components/Dropdown.react.js b/packages/dash-core-components/src/components/Dropdown.react.js index 2d906afc83..79271fce9c 100644 --- a/packages/dash-core-components/src/components/Dropdown.react.js +++ b/packages/dash-core-components/src/components/Dropdown.react.js @@ -1,6 +1,7 @@ import R from 'ramda'; import React, {Component, PropTypes} from 'react'; -import ReactDropdown from 'react-select'; +import ReactDropdown from 'react-virtualized-select'; +import createFilterOptions from 'react-select-fast-filter-options'; const DELIMETER = ','; @@ -17,11 +18,19 @@ const DELIMETER = ','; export default class Dropdown extends Component { constructor(props) { super(props); - this.state = {value: props.value}; + this.state = { + value: props.value, + filterOptions: createFilterOptions({options: props.options}) + }; } componentWillReceiveProps(newProps) { this.setState({value: newProps.value}); + if (newProps.options !== this.props.options) { + this.setState({ + filterOptions: createFilterOptions(newProps.options) + }); + } } render() { @@ -36,6 +45,7 @@ export default class Dropdown extends Component { return (
{