Skip to content

Commit

Permalink
Merge pull request #21 from jenny-s51/upgradeSelectableDemo
Browse files Browse the repository at this point in the history
Upgrade Selectable example
  • Loading branch information
wise-king-sullyman authored Dec 5, 2023
2 parents b62b369 + 281ba38 commit c84ce2b
Show file tree
Hide file tree
Showing 7 changed files with 374 additions and 185 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"@typescript-eslint/parser": "^5.59.7",
"prettier": "2.8.8",
"jest": "^29.5.0",
"jest-transform-stub": "2.0.0",
"babel-jest": "^29.5.0",
"@babel/core": "^7.21.8",
"@babel/preset-env": "^7.21.5",
Expand Down
230 changes: 94 additions & 136 deletions packages/module/patternfly-docs/content/examples/Selectable.tsx
Original file line number Diff line number Diff line change
@@ -1,153 +1,111 @@
import React from 'react';
import { debounce } from '@patternfly/react-core';
import { headerCol, TableGridBreakpoint } from '@patternfly/react-table';
import { Table as TableDeprecated, TableHeader as TableHeaderDeprecated } from '@patternfly/react-table/deprecated';

import { CellMeasurerCache, CellMeasurer } from 'react-virtualized';
import { AutoSizer, VirtualTableBody } from '@patternfly/react-virtualized-extension';
import { Table, Thead, Tr, Th, Td, Caption, TableGridBreakpoint } from '@patternfly/react-table';

export class SelectableExample extends React.Component {
constructor(props) {
super(props);
const rows = [];
for (let i = 0; i < 100; i++) {
rows.push({
selected: false,
id: `selectable-row-${i}`,
cells: [`one-${i}`, `two-${i}`, `three-${i}`, `four-${i}`, `five-${i}`]
});
}
export const SelectableTableVirtualized: React.FunctionComponent = () => {
// this StringArray type is just needed because something in our documentation framework crashes when it encounters
// a string[][] type
type StringArray = string[];
const rows: StringArray[] = [];

this.selectableVirtualBody = null;
for (let i = 0; i < 100; i++) {
rows.push([`one-${i}`, `two-${i}`, `three-${i}`, `four-${i}`, `five-${i}`]);
}

this.state = {
columns: [
// headerCol transform adds checkbox column with pf-m-2-sm, pf-m-1-md+ column space
{
title: 'Repositories',
cellTransforms: [headerCol()],
props: { className: 'pf-m-5-col-on-sm pf-m-4-col-on-md pf-m-3-col-on-lg pf-m-2-col-on-xl' }
},
{
title: 'Pull requests',
props: { className: 'pf-m-5-col-on-sm pf-m-4-col-on-md pf-m-4-col-on-lg pf-m-3-col-on-xl' }
},
{
title: 'Workspaces',
props: { className: 'pf-m-2-col-on-lg pf-m-2-col-on-xl pf-m-hidden pf-m-visible-on-lg' }
},
{ title: 'Last Commit', props: { className: 'pf-m-3-col-on-xl pf-m-hidden pf-m-visible-on-xl' } }
],
rows
};
const selectableRepos = rows;

this.onSelect = this.onSelect.bind(this);
this._handleResize = debounce(this._handleResize.bind(this), 100);
}
const [selectedRepoNames, setSelectedRepoNames] = React.useState<string[]>([]);

componentDidMount() {
// re-render after resize
window.addEventListener('resize', this._handleResize);
}
const setRepoSelected = (repo: string, isSelecting = true) =>
setSelectedRepoNames((prevSelected) => {
const otherSelectedRepoNames = prevSelected.filter((r) => r !== repo);
return isSelecting ? [...otherSelectedRepoNames, repo] : otherSelectedRepoNames;
});

componentWillUnmount() {
window.removeEventListener('resize', this._handleResize);
}
const columns = ['Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last Commit'];

_handleResize() {
this.forceUpdate();
}
const selectAllRepos = (isSelecting = true) => setSelectedRepoNames(isSelecting ? rows.map((item) => item[0]) : []);

onSelect(event, isSelected, virtualRowIndex, rowData) {
let rows;
if (virtualRowIndex === -1) {
rows = this.state.rows.map((oneRow) => {
oneRow.selected = isSelected;
return oneRow;
});
} else {
rows = [...this.state.rows];
const rowIndex = rows.findIndex((r) => r.id === rowData.id);
rows[rowIndex] = { ...rows[rowIndex], selected: isSelected };
}
this.setState({
rows
});
this.selectableVirtualBody.forceUpdateVirtualGrid();
}
const areAllReposSelected = selectedRepoNames.length === selectableRepos.length;
const isRepoSelected = (repo: string) => selectedRepoNames.includes(repo);

render() {
const { columns, rows } = this.state;
const [recentSelectedRowIndex, setRecentSelectedRowIndex] = React.useState<number | null>(null);

const measurementCache = new CellMeasurerCache({
fixedWidth: true,
minHeight: 44,
keyMapper: (rowIndex) => rowIndex
});
const onSelectRepo = (repo: string, rowIndex: number, isSelecting: boolean) => {
if (recentSelectedRowIndex !== null) {
const numberSelected = rowIndex - recentSelectedRowIndex;
const intermediateIndexes =
numberSelected > 0
? Array.from(new Array(numberSelected + 1), (_x, i) => i + recentSelectedRowIndex)
: Array.from(new Array(Math.abs(numberSelected) + 1), (_x, i) => i + rowIndex);
intermediateIndexes.forEach(() => setRepoSelected(repo, isSelecting));
} else {
setRepoSelected(repo, isSelecting);
}
setRecentSelectedRowIndex(rowIndex);
};

const rowRenderer = ({ index, _isScrolling, key, style, parent }) => {
const { rows, columns } = this.state;
const measurementCache = new CellMeasurerCache({
fixedWidth: true,
minHeight: 44,
keyMapper: (rowIndex) => rowIndex
});

return (
<CellMeasurer cache={measurementCache} columnIndex={0} key={key} parent={parent} rowIndex={index}>
<tr data-id={index} style={style} role="row">
<td data-key="0" className="pf-v5-c-table__check" role="gridcell">
<input
type="checkbox"
aria-label={`Select row ${index}`}
checked={rows[index].selected}
onChange={(e) => {
this.onSelect(e, e.target.checked, 0, { id: rows[index].id });
}}
/>
</td>
<td className={columns[0].props.className} role="gridcell">
{rows[index].cells[0]}
</td>
<td className={columns[1].props.className} role="gridcell">
{rows[index].cells[1]}
</td>
<td className={columns[2].props.className} role="gridcell">
{rows[index].cells[2]}
</td>
<td className={columns[3].props.className} role="gridcell">
{rows[index].cells[3]}
</td>
</tr>
</CellMeasurer>
);
};
const rowRenderer = ({ index: rowIndex, _isScrolling, key, style, parent }) => (
<CellMeasurer cache={measurementCache} columnIndex={0} key={key} parent={parent} rowIndex={rowIndex}>
<Tr style={style}>
<Td
key={`${rowIndex}_0`}
select={{
rowIndex,
onSelect: (_event, isSelecting) => onSelectRepo(rows[rowIndex][0], rowIndex, isSelecting),
isSelected: isRepoSelected(rows[rowIndex][0])
}}
/>
{columns.map((col, index) => (
<Td key={`${rowIndex}-${index + 1}`}>{rows[rowIndex][index]}</Td>
))}
</Tr>
</CellMeasurer>
);

return (
<div aria-label="Scrollable Table" className="pf-v5-c-scrollablegrid">
<TableDeprecated
caption="Selectable Virtualized Table"
cells={columns}
rows={rows}
gridBreakPoint={TableGridBreakpoint.none}
onSelect={this.onSelect}
aria-rowcount={rows.length}
>
<TableHeaderDeprecated />
</TableDeprecated>
<AutoSizer disableHeight>
{({ width }) => (
<VirtualTableBody
ref={(ref) => (this.selectableVirtualBody = ref)}
className="pf-v5-c-table pf-v5-c-virtualized pf-v5-c-window-scroller"
deferredMeasurementCache={measurementCache}
rowHeight={measurementCache.rowHeight}
height={400}
overscanRowCount={2}
columnCount={1}
rows={rows}
rowCount={rows.length}
rowRenderer={rowRenderer}
width={width}
role="grid"
return (
<div aria-label="Scrollable Table" className="pf-v5-c-scrollablegrid">
<Table gridBreakPoint={TableGridBreakpoint.none} aria-rowcount={rows.length}>
<Caption>Selectable Virtualized Table</Caption>
<Thead>
<Tr>
<Th
select={{
onSelect: (_event, isSelecting) => selectAllRepos(isSelecting),
isSelected: areAllReposSelected
}}
/>
)}
</AutoSizer>
</div>
);
}
}
{columns.map((col, index) => (
<Th key={++index}>{col}</Th>
))}
</Tr>
</Thead>
</Table>
<AutoSizer disableHeight>
{({ width }) => (
<VirtualTableBody
className="pf-v5-c-table pf-v5-c-virtualized pf-v5-c-window-scroller"
deferredMeasurementCache={measurementCache}
rowHeight={measurementCache.rowHeight}
height={400}
overscanRowCount={2}
columnCount={1}
rows={rows}
rowCount={rows.length}
rowRenderer={rowRenderer}
width={width}
role="grid"
/>
)}
</AutoSizer>
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import FilterIcon from '@patternfly/react-icons/dist/esm/icons/filter-icon';
import { CellMeasurerCache, CellMeasurer} from 'react-virtualized';
import { AutoSizer, VirtualTableBody, WindowScroller } from '@patternfly/react-virtualized-extension';
import { Table as TableDeprecated, TableHeader as TableHeaderDeprecated } from '@patternfly/react-table/deprecated';
import { Table, Thead, Tr, Th, Td, Caption, TableGridBreakpoint } from '@patternfly/react-table';
import {
Dropdown as DropdownDeprecated,
DropdownItem as DropdownItemDeprecated,
Expand Down
Loading

0 comments on commit c84ce2b

Please sign in to comment.