From f720dbbb6162b996464c7cf6cf922d4d0d1887c1 Mon Sep 17 00:00:00 2001 From: Patrick Riley Date: Fri, 25 Jan 2019 11:09:24 -0500 Subject: [PATCH] virtualized sorting --- .../src/components/Virtualized/Body.js | 68 +++++++++++------- .../src/components/Virtualized/BodyWrapper.js | 17 +++-- .../Virtualized/Virtualized.docs.js | 16 ++++- .../Virtualized/examples/SortableExample.js | 72 +++++++++++++++++++ 4 files changed, 139 insertions(+), 34 deletions(-) create mode 100644 packages/patternfly-4/react-virtualized-extension/src/components/Virtualized/examples/SortableExample.js diff --git a/packages/patternfly-4/react-virtualized-extension/src/components/Virtualized/Body.js b/packages/patternfly-4/react-virtualized-extension/src/components/Virtualized/Body.js index d932e483f52..84bb86591bd 100644 --- a/packages/patternfly-4/react-virtualized-extension/src/components/Virtualized/Body.js +++ b/packages/patternfly-4/react-virtualized-extension/src/components/Virtualized/Body.js @@ -24,7 +24,27 @@ class Body extends React.Component { super(props); this.measuredRows = {}; // row key -> measurement - this.ref = null; + + this.ref = React.createRef(); + + this.scrollTo = index => { + const startIndex = parseInt(index, 10); + + if (startIndex >= 0) { + const startHeight = + calculateAverageHeight({ + measuredRows: this.measuredRows, + rows: props.rows, + rowKey: props.rowKey + }) * startIndex; + + this.scrollTop = startHeight; + this.ref.current.scrollTop = startHeight; + + this.setState(this.calculateRows(this.props)); + } + }; + this.scrollTop = 0; this.initialMeasurement = true; this.timeoutId = 0; @@ -58,6 +78,7 @@ class Body extends React.Component { return props.height || props.style.maxHeight; } + // todo: convert `componentWillReceiveProps` to `getDerivedStateFromProps` componentWillReceiveProps(nextProps) { if (!isEqual(this.props.rows, nextProps.rows) || this.getHeight(this.props) !== this.getHeight(nextProps)) { if (process.env.NODE_ENV !== 'production' && typeof window !== 'undefined' && window.LOG_VIRTUALIZED) { @@ -120,16 +141,13 @@ class Body extends React.Component { }; }, rowsToRender, - // todo: revisit passing ref to scrolling container and finding offset - // ref: body => { - // this.ref = body && body.getRef().getRef(); - // }, onScroll: this.onScroll }); return ( { - const startIndex = parseInt(index, 10); + // ref.scrollTo = index => { + // const startIndex = parseInt(index, 10); - if (startIndex >= 0) { - const startHeight = - calculateAverageHeight({ - measuredRows: this.measuredRows, - rows: this.props.rows, - rowKey: this.props.rowKey - }) * startIndex; + // if (startIndex >= 0) { + // const startHeight = + // calculateAverageHeight({ + // measuredRows: this.measuredRows, + // rows: this.props.rows, + // rowKey: this.props.rowKey + // }) * startIndex; - this.scrollTop = startHeight; - this.ref.scrollTop = startHeight; + // this.scrollTop = startHeight; + // this.ref.scrollTop = startHeight; - this.setState(this.calculateRows(this.props)); - } - }; + // this.setState(this.calculateRows(this.props)); + // } + // }; - return ref; - } + // return ref; + // } calculateRows(props) { return calculateRows({ scrollTop: this.scrollTop, @@ -223,7 +241,7 @@ class Body extends React.Component { const VirtualizedBody = props => ( - {({ headerData, rows }) => } + {({ headerData, rows }) => } ); diff --git a/packages/patternfly-4/react-virtualized-extension/src/components/Virtualized/BodyWrapper.js b/packages/patternfly-4/react-virtualized-extension/src/components/Virtualized/BodyWrapper.js index 5ce15c200de..8ae97e0089a 100644 --- a/packages/patternfly-4/react-virtualized-extension/src/components/Virtualized/BodyWrapper.js +++ b/packages/patternfly-4/react-virtualized-extension/src/components/Virtualized/BodyWrapper.js @@ -8,10 +8,9 @@ const VirtualizedBodyWrapper = inputRows => { class VirtualizedBody extends Component { constructor(props) { super(props); - this.ref = React.createRef(); } render() { - const { children, startHeight, endHeight, showExtraRow, ...props } = this.props; + const { children, bodyRef, startHeight, endHeight, showExtraRow, ...props } = this.props; const startRow = tr({ key: 'start-row', style: { @@ -43,7 +42,7 @@ const VirtualizedBodyWrapper = inputRows => { 'tbody', { ...props, - ref: this.ref, + ref: bodyRef, className: css( inputRows.some(row => row.isOpen && !row.hasOwnProperty('parent')) && styles.modifiers.expanded ) @@ -52,7 +51,7 @@ const VirtualizedBodyWrapper = inputRows => { ); } getRef() { - return this.ref; + return this.props.tableBodyRef; } } VirtualizedBodyWrapper.contextTypes = bodyWrapperContextTypes; @@ -64,8 +63,14 @@ const VirtualizedBodyWrapper = inputRows => { const VirtualizedBodyWithContext = props => ( - {({ startHeight, endHeight, showExtraRow }) => ( - + {({ bodyRef, startHeight, endHeight, showExtraRow }) => ( + )} ); diff --git a/packages/patternfly-4/react-virtualized-extension/src/components/Virtualized/Virtualized.docs.js b/packages/patternfly-4/react-virtualized-extension/src/components/Virtualized/Virtualized.docs.js index ee532a459bd..28b99660996 100644 --- a/packages/patternfly-4/react-virtualized-extension/src/components/Virtualized/Virtualized.docs.js +++ b/packages/patternfly-4/react-virtualized-extension/src/components/Virtualized/Virtualized.docs.js @@ -1,14 +1,24 @@ -import { AutoSizer } from '@patternfly/react-virtualized-extension'; +import { + AutoSizer, + VirtualizedBody, + VirtualizedBodyWrapper, + VirtualizedRowWrapper +} from '@patternfly/react-virtualized-extension'; import AutoSizerExample from './examples/AutoSizerExample'; import VirtualizedExample from './examples/VirtualizedExample'; +import SortableExample from './examples/SortableExample'; export default { title: 'Virtualized', components: { - AutoSizer + AutoSizer, + VirtualizedBody, + VirtualizedBodyWrapper, + VirtualizedRowWrapper }, examples: [ { component: AutoSizerExample, title: 'Simple AutoSizer Example' }, - { component: VirtualizedExample, title: 'Simple Virtualized Example' } + { component: VirtualizedExample, title: 'Simple Virtualized Example' }, + { component: SortableExample, title: 'Sortable Virtualized Example' } ] }; diff --git a/packages/patternfly-4/react-virtualized-extension/src/components/Virtualized/examples/SortableExample.js b/packages/patternfly-4/react-virtualized-extension/src/components/Virtualized/examples/SortableExample.js new file mode 100644 index 00000000000..e619a853447 --- /dev/null +++ b/packages/patternfly-4/react-virtualized-extension/src/components/Virtualized/examples/SortableExample.js @@ -0,0 +1,72 @@ +import React from 'react'; +import { Table, TableHeader, sortable, SortByDirection } from '@patternfly/react-table'; +import { + VirtualizedBody, + VirtualizedBodyWrapper, + VirtualizedRowWrapper +} from '@patternfly/react-virtualized-extension'; +import './sample.css'; + +class SortableExample extends React.Component { + static title = 'Simple Table'; + constructor(props) { + super(props); + + this.tableBody = React.createRef(); + + const rows = []; + for (let i = 0; i < 100; i++) { + rows.push({ + id: i, + cells: [`one-${i}`, `two-${i}`, `three-${i}`, `four-${i}`, `five-${i}`] + }); + } + this.state = { + columns: [ + { title: 'Repositories', transforms: [sortable], props: { style: { width: '20%' } } }, + { title: 'Branches', props: { style: { width: '20%' } } }, + { title: 'Pull requests', transforms: [sortable], props: { style: { width: '20%' } } }, + { title: 'Workspaces', props: { style: { width: '20%' } } }, + { title: 'Last Commit', props: { style: { width: '20%' } } } + ], + rows, + sortBy: {} + }; + this.onSort = this.onSort.bind(this); + } + + onSort(_event, index, direction) { + const sortedRows = this.state.rows.sort( + (a, b) => (a.cells[index] < b.cells[index] ? -1 : a.cells[index] > b.cells[index] ? 1 : 0) + ); + this.tableBody.current.scrollTo(0); + this.setState({ + sortBy: { + index, + direction + }, + rows: direction === SortByDirection.asc ? sortedRows : sortedRows.reverse() + }); + } + + render() { + const { columns, rows, sortBy } = this.state; + + return ( + + + +
+ ); + } +} + +export default SortableExample;