mirror of
https://github.com/gosticks/react-table.git
synced 2026-07-01 18:10:02 +00:00
A few HOC examples for react-table.
Not really integrated with the whole codesandbox.io approach.
This commit is contained in:
6502
docs/public/au_500_tree.json
Normal file
6502
docs/public/au_500_tree.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -7,8 +7,17 @@ import '../../react-table.css'
|
||||
|
||||
import Readme from './stories/Readme.js'
|
||||
|
||||
import { TreeTable, CheckboxTable } from './examples/index'
|
||||
|
||||
const exampleStories = [
|
||||
// examples
|
||||
{ name: 'TreeTable', component: TreeTable },
|
||||
{ name: 'CheckboxTable', component: CheckboxTable },
|
||||
];
|
||||
|
||||
const stories = [
|
||||
{ name: 'Readme', component: Readme },
|
||||
|
||||
{ name: 'Simple Table', component: CodeSandbox('X6npLXPRW') },
|
||||
{
|
||||
name: 'Cell Renderers & Custom Components',
|
||||
@@ -51,6 +60,10 @@ const stories = [
|
||||
name: 'Multiple Pagers (Top and Bottom)',
|
||||
component: CodeSandbox('VEZ8OgvX'),
|
||||
},
|
||||
|
||||
// other examples
|
||||
...exampleStories,
|
||||
|
||||
]
|
||||
|
||||
export default class App extends React.Component {
|
||||
@@ -63,7 +76,7 @@ export default class App extends React.Component {
|
||||
height: '100%',
|
||||
}}
|
||||
pathPrefix='story/'
|
||||
StoryWrapper={props => (
|
||||
StoryWrapper={props =>
|
||||
<defaultProps.StoryWrapper
|
||||
css={{
|
||||
padding: 0,
|
||||
@@ -95,8 +108,7 @@ export default class App extends React.Component {
|
||||
position: 'relative',
|
||||
}}
|
||||
/>
|
||||
</defaultProps.StoryWrapper>
|
||||
)}
|
||||
</defaultProps.StoryWrapper>}
|
||||
stories={stories}
|
||||
/>
|
||||
)
|
||||
|
||||
88
docs/src/examples/checkbox/checkboxHOC.js
Normal file
88
docs/src/examples/checkbox/checkboxHOC.js
Normal file
@@ -0,0 +1,88 @@
|
||||
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default (Component) => {
|
||||
|
||||
const wrapper = class RTCheckboxTable extends React.Component {
|
||||
// we only need a Component so we can get the 'ref' - pure components can't get a 'ref'
|
||||
|
||||
rowSelector = (row) =>
|
||||
{
|
||||
if(!row || !row.hasOwnProperty(this.props.keyField)) return null;
|
||||
const checked = this.props.isSelected(row[this.props.keyField]);
|
||||
return (
|
||||
<input
|
||||
type='checkbox'
|
||||
checked={checked}
|
||||
onClick={(e)=>{
|
||||
const { shiftKey } = e;
|
||||
e.stopPropagation();
|
||||
this.props.toggleSelection(row[this.props.keyField],shiftKey,row);
|
||||
}}
|
||||
onChange={()=>{}}
|
||||
value=''
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
headSelector = (row) =>
|
||||
{
|
||||
const checked = this.props.selectAll;
|
||||
return (
|
||||
<input
|
||||
type='checkbox'
|
||||
checked={checked}
|
||||
onClick={(e)=>{
|
||||
e.stopPropagation();
|
||||
this.props.toggleAll();
|
||||
}}
|
||||
onChange={()=>{}}
|
||||
value=''
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// this is so we can expose the underlying ReactTable to get at the sortedData for selectAll
|
||||
getWrappedInstance = ()=>this.wrappedInstance
|
||||
|
||||
render()
|
||||
{
|
||||
const { columns:originalCols, isSelected, toggleSelection, toggleAll, keyField, selectAll, ...rest } = this.props;
|
||||
const { rowSelector, headSelector, } = this;
|
||||
const select = {
|
||||
id: '_selector',
|
||||
accessor: ()=>'x', // this value is not important
|
||||
Header: headSelector,
|
||||
Cell: (ci) => { return rowSelector(ci.original); },
|
||||
width: 30,
|
||||
filterable: false,
|
||||
sortable: false,
|
||||
resizable: false,
|
||||
style: { textAlign: 'center' },
|
||||
}
|
||||
const columns = [
|
||||
select,
|
||||
...originalCols,
|
||||
];
|
||||
const extra = {
|
||||
columns,
|
||||
};
|
||||
return (
|
||||
<Component {...rest} {...extra} ref={(r)=>this.wrappedInstance=r}/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
wrapper.displayName = 'RTCheckboxTable';
|
||||
wrapper.defaultProps =
|
||||
{
|
||||
keyField: '_id',
|
||||
isSelected: (key)=>{ console.log('No isSelected handler provided:',{key})},
|
||||
selectAll: false,
|
||||
toggleSelection: (key, shift, row)=>{ console.log('No toggleSelection handler provided:', { key, shift, row }) },
|
||||
toggleAll: () => { console.log('No toggleAll handler provided.') },
|
||||
}
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
160
docs/src/examples/checkbox/index.js
Normal file
160
docs/src/examples/checkbox/index.js
Normal file
@@ -0,0 +1,160 @@
|
||||
|
||||
import React from 'react';
|
||||
import shortid from 'shortid';
|
||||
|
||||
import ReactTable from '../../../../lib/index'
|
||||
import '../../../../react-table.css'
|
||||
|
||||
import checkboxTableHOC from './checkboxHOC';
|
||||
|
||||
const CheckboxTable = checkboxTableHOC(ReactTable);
|
||||
|
||||
async function getData()
|
||||
{
|
||||
const result = await ( await fetch('/au_500_tree.json') ).json();
|
||||
// we are adding a unique ID to the data for tracking the selected records
|
||||
return result.map((item)=>{
|
||||
const _id = shortid.generate();
|
||||
return {
|
||||
_id,
|
||||
...item,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getColumns(data)
|
||||
{
|
||||
const columns = [];
|
||||
const sample = data[0];
|
||||
for(let key in sample)
|
||||
{
|
||||
if(key==='_id') continue;
|
||||
columns.push({
|
||||
accessor: key,
|
||||
Header: key,
|
||||
})
|
||||
}
|
||||
return columns;
|
||||
}
|
||||
|
||||
export class ComponentTest extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state =
|
||||
{
|
||||
data: null,
|
||||
columns: null,
|
||||
selection: [],
|
||||
selectAll: false,
|
||||
};
|
||||
}
|
||||
componentDidMount()
|
||||
{
|
||||
getData().then((data)=>{
|
||||
const columns = getColumns(data);
|
||||
this.setState({ data, columns });
|
||||
});
|
||||
}
|
||||
toggleSelection = (key,shift,row) => {
|
||||
/*
|
||||
Implementation of how to manage the selection state is up to the developer.
|
||||
This implementation uses an array stored in the component state.
|
||||
Other implementations could use object keys, a Javascript Set, or Redux... etc.
|
||||
*/
|
||||
// start off with the existing state
|
||||
let selection = [
|
||||
...this.state.selection
|
||||
];
|
||||
const keyIndex = selection.indexOf(key);
|
||||
// check to see if the key exists
|
||||
if(keyIndex>=0) {
|
||||
// it does exist so we will remove it using destructing
|
||||
selection = [
|
||||
...selection.slice(0,keyIndex),
|
||||
...selection.slice(keyIndex+1)
|
||||
]
|
||||
} else {
|
||||
// it does not exist so add it
|
||||
selection.push(key);
|
||||
}
|
||||
// update the state
|
||||
this.setState({selection});
|
||||
}
|
||||
toggleAll = () => {
|
||||
/*
|
||||
'toggleAll' is a tricky concept with any filterable table
|
||||
do you just select ALL the records that are in your data?
|
||||
OR
|
||||
do you only select ALL the records that are in the current filtered data?
|
||||
|
||||
The latter makes more sense because 'selection' is a visual thing for the user.
|
||||
This is especially true if you are going to implement a set of external functions
|
||||
that act on the selected information (you would not want to DELETE the wrong thing!).
|
||||
|
||||
So, to that end, access to the internals of ReactTable are required to get what is
|
||||
currently visible in the table (either on the current page or any other page).
|
||||
|
||||
The HOC provides a method call 'getWrappedInstance' to get a ref to the wrapped
|
||||
ReactTable and then get the internal state and the 'sortedData'.
|
||||
That can then be iterrated to get all the currently visible records and set
|
||||
the selection state.
|
||||
*/
|
||||
const selectAll = this.state.selectAll?false:true;
|
||||
const selection = [];
|
||||
if(selectAll)
|
||||
{
|
||||
// we need to get at the internals of ReactTable
|
||||
const wrappedInstance = this.checkboxTable.getWrappedInstance();
|
||||
// the 'sortedData' property contains the currently accessible records based on the filter and sort
|
||||
const currentRecords = wrappedInstance.getResolvedState().sortedData;
|
||||
// we just push all the IDs onto the selection array
|
||||
currentRecords.forEach((item)=>{
|
||||
selection.push(item._original._id);
|
||||
})
|
||||
}
|
||||
this.setState({selectAll,selection})
|
||||
}
|
||||
isSelected = (key) => {
|
||||
/*
|
||||
Instead of passing our external selection state we provide an 'isSelected'
|
||||
callback and detect the selection state ourselves. This allows any implementation
|
||||
for selection (either an array, object keys, or even a Javascript Set object).
|
||||
*/
|
||||
return this.state.selection.includes(key);
|
||||
}
|
||||
logSelection = () => {
|
||||
console.log('selection:',this.state.selection);
|
||||
}
|
||||
render(){
|
||||
const { toggleSelection, toggleAll, isSelected, logSelection } = this;
|
||||
const { data, columns, selectAll } = this.state;
|
||||
const extraProps =
|
||||
{
|
||||
selectAll,
|
||||
isSelected,
|
||||
toggleAll,
|
||||
toggleSelection,
|
||||
}
|
||||
return (
|
||||
<div style={{ padding: '10px'}}>
|
||||
<h1>react-table - Checkbox Table</h1>
|
||||
<button onClick={logSelection}>Log Selection to Console</button>
|
||||
{` (${this.state.selection.length}) selected`}
|
||||
{
|
||||
data?
|
||||
<CheckboxTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
ref={(r)=>this.checkboxTable = r}
|
||||
className="-striped -highlight"
|
||||
{...extraProps}
|
||||
/>
|
||||
:null
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// export default treeTableHOC(ComponentTest);
|
||||
export default ComponentTest;
|
||||
8
docs/src/examples/index.js
Normal file
8
docs/src/examples/index.js
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
import TreeTable from './treetable';
|
||||
import CheckboxTable from './checkbox';
|
||||
|
||||
export {
|
||||
TreeTable,
|
||||
CheckboxTable,
|
||||
}
|
||||
80
docs/src/examples/treetable/index.js
Normal file
80
docs/src/examples/treetable/index.js
Normal file
@@ -0,0 +1,80 @@
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import ReactTable from '../../../../lib/index'
|
||||
import '../../../../react-table.css'
|
||||
|
||||
import treeTableHOC from './treeTableHOC';
|
||||
|
||||
async function getData()
|
||||
{
|
||||
const result = await ( await fetch('/au_500_tree.json') ).json();
|
||||
return result;
|
||||
}
|
||||
|
||||
function getColumns(data,pivotBy)
|
||||
{
|
||||
const columns = [];
|
||||
const sample = data[0];
|
||||
for(let key in sample)
|
||||
{
|
||||
columns.push({
|
||||
accessor: key,
|
||||
Header: key,
|
||||
})
|
||||
}
|
||||
return columns;
|
||||
}
|
||||
|
||||
export class ComponentTest extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state =
|
||||
{
|
||||
data: null,
|
||||
columns: null,
|
||||
pivotBy: null, // ["firstName", "lastName"],
|
||||
};
|
||||
}
|
||||
componentDidMount()
|
||||
{
|
||||
getData().then((data)=>{
|
||||
// console.log('cwm data:',data);
|
||||
const pivotBy = ['state','post','city'];
|
||||
const columns = getColumns(data,pivotBy);
|
||||
// console.log('cwm cols:',columns);
|
||||
this.setState({data,columns,pivotBy});
|
||||
});
|
||||
}
|
||||
showState = ()=>
|
||||
{
|
||||
console.log('state:',this.reactTable.getResolvedState());
|
||||
}
|
||||
render(){
|
||||
const { data, columns, pivotBy } = this.state;
|
||||
const extraProps =
|
||||
{
|
||||
data,
|
||||
columns,
|
||||
pivotBy,
|
||||
}
|
||||
const TreeTable = treeTableHOC(ReactTable);
|
||||
return (
|
||||
<div style={{ padding: '10px'}}>
|
||||
<h1>react-table - Tree Table</h1>
|
||||
{
|
||||
data?
|
||||
<TreeTable
|
||||
ref={(r)=>this.reactTable=r}
|
||||
className="-striped -highlight"
|
||||
defaultPageSize={5}
|
||||
{...extraProps}
|
||||
/>
|
||||
:null
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ComponentTest;
|
||||
58
docs/src/examples/treetable/treeTableHOC.js
Normal file
58
docs/src/examples/treetable/treeTableHOC.js
Normal file
@@ -0,0 +1,58 @@
|
||||
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default (Component) => {
|
||||
const wrapper = (componentProps) => {
|
||||
const TrComponent = (props) => {
|
||||
const { ri, ...rest } = props;
|
||||
if(ri && ri.groupedByPivot) {
|
||||
const cell = props.children[ri.level];
|
||||
|
||||
cell.props.style.flex = 'unset';
|
||||
cell.props.style.width = '100%';
|
||||
cell.props.style.maxWidth = 'unset';
|
||||
cell.props.style.paddingLeft = `${componentProps.treeTableIndent*ri.level}px`;
|
||||
cell.props.style.backgroundColor = '#DDD';
|
||||
cell.props.style.borderBottom = '1px solid rgba(128,128,128,0.2)';
|
||||
|
||||
return <div {...rest}>{cell}</div>;
|
||||
}
|
||||
return <Component.defaultProps.TrComponent {...rest} />;
|
||||
}
|
||||
|
||||
const getTrProps = (state,ri,ci,instance) => {
|
||||
return {ri};
|
||||
}
|
||||
|
||||
const { columns, ...rest } = componentProps;
|
||||
const extra = {
|
||||
columns: columns.map((col)=>{
|
||||
let column = col;
|
||||
if(rest.pivotBy && rest.pivotBy.includes(col.accessor))
|
||||
{
|
||||
column = {
|
||||
accessor: col.accessor,
|
||||
width: `${componentProps.treeTableIndent}px`,
|
||||
show: false,
|
||||
Header: '',
|
||||
}
|
||||
}
|
||||
return column;
|
||||
}),
|
||||
TrComponent,
|
||||
getTrProps,
|
||||
};
|
||||
|
||||
return (
|
||||
<Component {...rest} {...extra} />
|
||||
)
|
||||
}
|
||||
wrapper.displayName = 'RTTreeTable';
|
||||
wrapper.defaultProps =
|
||||
{
|
||||
treeTableRowBackground: '#EEE',
|
||||
treeTableIndent: 10,
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
34
docs/src/examples/utils.js
Normal file
34
docs/src/examples/utils.js
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
import namor from "namor";
|
||||
|
||||
const range = len => {
|
||||
const arr = [];
|
||||
for (let i = 0; i < len; i++) {
|
||||
arr.push(i);
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
|
||||
const newPerson = () => {
|
||||
const statusChance = Math.random();
|
||||
return {
|
||||
firstName: namor.generate({ words: 1, numbers: 0 }),
|
||||
lastName: namor.generate({ words: 1, numbers: 0 }),
|
||||
age: Math.floor(Math.random() * 30),
|
||||
visits: Math.floor(Math.random() * 100),
|
||||
progress: Math.floor(Math.random() * 100),
|
||||
status:
|
||||
statusChance > 0.66
|
||||
? "relationship"
|
||||
: statusChance > 0.33 ? "complicated" : "single"
|
||||
};
|
||||
};
|
||||
|
||||
export function makeData(len = 5553) {
|
||||
return range(len).map(d => {
|
||||
return {
|
||||
...newPerson(),
|
||||
children: range(10).map(newPerson)
|
||||
};
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user