docs(examples/material-ui-enhanced-table): Add more Material UI table (#1847)

* docs(examples/material-ui-enhanced-table): add more Material UI table

This enhanced Material UI table demonstrates client side pagination, sorting, global search, add
row, and delete row.

* Update EnhancedTable.js

Co-authored-by: Tanner Linsley <tannerlinsley@gmail.com>
This commit is contained in:
Steve Liang 2020-02-14 12:19:55 -08:00 committed by GitHub
parent 164b3d6b7e
commit 2bf99aaea0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 11453 additions and 14 deletions

View File

@ -1,21 +1,13 @@
{
"dist/index.js": {
"bundled": 113198,
"minified": 52513,
"gzipped": 13835
"bundled": 113244,
"minified": 52531,
"gzipped": 13840
},
"dist/index.es.js": {
"bundled": 112261,
"minified": 51677,
"gzipped": 13669,
"bundled": 126701,
"minified": 59700,
"gzipped": 15373
},
"dist/index.es.js": {
"bundled": 125788,
"minified": 58888,
"gzipped": 15205,
"bundled": 112307,
"minified": 51695,
"gzipped": 13674,
"treeshaked": {
"rollup": {
"code": 80,

View File

@ -73,6 +73,9 @@
- Material-UI
- [Source](https://github.com/tannerlinsley/react-table/tree/master/examples/material-UI-components)
- [Open in CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/material-UI-components)
- Material-UI Enhanced Table
- [Source](https://github.com/tannerlinsley/react-table/tree/master/examples/material-UI-enhanced-table)
- [Open in CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/material-UI-enhanced-table)
- [ ] Styled-Components
- [ ] CSS
- [ ] Bootstrap

View File

@ -0,0 +1,3 @@
{
"presets": ["react-app"]
}

View File

@ -0,0 +1 @@
SKIP_PREFLIGHT_CHECK=true

View File

@ -0,0 +1,7 @@
{
"extends": ["react-app", "prettier"],
"rules": {
// "eqeqeq": 0,
// "jsx-a11y/anchor-is-valid": 0
}
}

View File

@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View File

@ -0,0 +1,29 @@
const path = require('path')
const resolveFrom = require('resolve-from')
const fixLinkedDependencies = config => {
config.resolve = {
...config.resolve,
alias: {
...config.resolve.alias,
react$: resolveFrom(path.resolve('node_modules'), 'react'),
'react-dom$': resolveFrom(path.resolve('node_modules'), 'react-dom'),
},
}
return config
}
const includeSrcDirectory = config => {
config.resolve = {
...config.resolve,
modules: [path.resolve('src'), ...config.resolve.modules],
}
return config
}
module.exports = [
['use-babel-config', '.babelrc'],
['use-eslint-config', '.eslintrc'],
fixLinkedDependencies,
// includeSrcDirectory,
]

View File

@ -0,0 +1,8 @@
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app) and Rescripts.
You can:
- [Open this example in a new CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/material-UI-enhanced-table)
- `yarn` and `yarn start` to run and edit the example
It demonstrates client side pagination, sorting, global search, add row, and delete row.

View File

@ -0,0 +1,37 @@
{
"private": true,
"scripts": {
"start": "rescripts start",
"build": "rescripts build",
"test": "rescripts test",
"eject": "rescripts eject"
},
"dependencies": {
"@material-ui/core": "^4.8.3",
"@material-ui/icons": "^4.5.1",
"namor": "^1.1.2",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-scripts": "3.0.1",
"react-table": "latest"
},
"devDependencies": {
"@rescripts/cli": "^0.0.11",
"@rescripts/rescript-use-babel-config": "^0.0.8",
"@rescripts/rescript-use-eslint-config": "^0.0.9",
"babel-eslint": "10.0.1",
"eslint-config-prettier": "^6.3.0"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

View File

@ -0,0 +1,15 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

View File

@ -0,0 +1,77 @@
import React from 'react'
import CssBaseline from '@material-ui/core/CssBaseline'
import EnhancedTable from './components/EnhancedTable'
import makeData from './makeData'
const App = () => {
const columns = React.useMemo(
() => [
{
Header: 'First Name',
accessor: 'firstName',
},
{
Header: 'Last Name',
accessor: 'lastName',
},
{
Header: 'Age',
accessor: 'age',
},
{
Header: 'Visits',
accessor: 'visits',
},
{
Header: 'Status',
accessor: 'status',
},
{
Header: 'Profile Progress',
accessor: 'progress',
},
],
[]
)
const [data, setData] = React.useState(React.useMemo(() => makeData(20), []))
const [skipPageReset, setSkipPageReset] = React.useState(false)
// We need to keep the table from resetting the pageIndex when we
// Update data. So we can keep track of that flag with a ref.
// When our cell renderer calls updateMyData, we'll use
// the rowIndex, columnId and new value to update the
// original data
const updateMyData = (rowIndex, columnId, value) => {
// We also turn on the flag to not reset the page
setSkipPageReset(true)
setData(old =>
old.map((row, index) => {
if (index === rowIndex) {
return {
...old[rowIndex],
[columnId]: value,
}
}
return row
})
)
}
return (
<div>
<CssBaseline />
<EnhancedTable
columns={columns}
data={data}
setData={setData}
updateMyData={updateMyData}
skipPageReset={skipPageReset}
/>
</div>
)
}
export default App

View File

@ -0,0 +1,9 @@
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
it('renders without crashing', () => {
const div = document.createElement('div')
ReactDOM.render(<App />, div)
ReactDOM.unmountComponentAtNode(div)
})

View File

@ -0,0 +1,152 @@
import React, { useState } from 'react'
import AddIcon from '@material-ui/icons/Add'
import Button from '@material-ui/core/Button'
import Dialog from '@material-ui/core/Dialog'
import DialogActions from '@material-ui/core/DialogActions'
import DialogContent from '@material-ui/core/DialogContent'
import DialogContentText from '@material-ui/core/DialogContentText'
import DialogTitle from '@material-ui/core/DialogTitle'
import IconButton from '@material-ui/core/IconButton'
import PropTypes from 'prop-types'
import Switch from '@material-ui/core/Switch'
import TextField from '@material-ui/core/TextField'
import Tooltip from '@material-ui/core/Tooltip'
const initialUser = {
firstName: '',
lastName: '',
age: 0,
visits: 0,
status: 'single',
progress: 0,
subRows: undefined,
}
const AddUserDialog = props => {
const [user, setUser] = useState(initialUser)
const { addUserHandler } = props
const [open, setOpen] = React.useState(false)
const [switchState, setSwitchState] = React.useState({
addMultiple: false,
})
const handleSwitchChange = name => event => {
setSwitchState({ ...switchState, [name]: event.target.checked })
}
const resetSwitch = () => {
setSwitchState({ addMultiple: false })
}
const handleClickOpen = () => {
setOpen(true)
}
const handleClose = () => {
setOpen(false)
resetSwitch()
}
const handleAdd = event => {
addUserHandler(user)
setUser(initialUser)
switchState.addMultiple ? setOpen(true) : setOpen(false)
}
const handleChange = name => ({ target: { value } }) => {
setUser({ ...user, [name]: value })
}
return (
<div>
<Tooltip title="Add">
<IconButton aria-label="add" onClick={handleClickOpen}>
<AddIcon />
</IconButton>
</Tooltip>
<Dialog
open={open}
onClose={handleClose}
aria-labelledby="form-dialog-title"
>
<DialogTitle id="form-dialog-title">Add User</DialogTitle>
<DialogContent>
<DialogContentText>Demo add item to react table.</DialogContentText>
<TextField
autoFocus
margin="dense"
label="First Name"
type="text"
fullWidth
value={user.firstName}
onChange={handleChange('firstName')}
/>
<TextField
margin="dense"
label="Last Name"
type="text"
fullWidth
value={user.lastName}
onChange={handleChange('lastName')}
/>
<TextField
margin="dense"
label="Age"
type="number"
fullWidth
value={user.age}
onChange={handleChange('age')}
/>
<TextField
margin="dense"
label="Visits"
type="number"
fullWidth
value={user.visits}
onChange={handleChange('visits')}
/>
<TextField
margin="dense"
label="Status"
type="text"
fullWidth
value={user.status}
onChange={handleChange('status')}
/>
<TextField
margin="dense"
label="Profile Progress"
type="number"
fullWidth
value={user.progress}
onChange={handleChange('progress')}
/>
</DialogContent>
<DialogActions>
<Tooltip title="Add multiple">
<Switch
checked={switchState.addMultiple}
onChange={handleSwitchChange('addMultiple')}
value="addMultiple"
inputProps={{ 'aria-label': 'secondary checkbox' }}
/>
</Tooltip>
<Button onClick={handleClose} color="primary">
Cancel
</Button>
<Button onClick={handleAdd} color="primary">
Add
</Button>
</DialogActions>
</Dialog>
</div>
)
}
AddUserDialog.propTypes = {
addUserHandler: PropTypes.func.isRequired,
}
export default AddUserDialog

View File

@ -0,0 +1,274 @@
import React from 'react'
import Checkbox from '@material-ui/core/Checkbox'
import MaUTable from '@material-ui/core/Table'
import PropTypes from 'prop-types'
import TableBody from '@material-ui/core/TableBody'
import TableCell from '@material-ui/core/TableCell'
import TableContainer from '@material-ui/core/TableContainer'
import TableFooter from '@material-ui/core/TableFooter'
import TableHead from '@material-ui/core/TableHead'
import TablePagination from '@material-ui/core/TablePagination'
import TablePaginationActions from './TablePaginationActions'
import TableRow from '@material-ui/core/TableRow'
import TableSortLabel from '@material-ui/core/TableSortLabel'
import TableToolbar from './TableToolbar'
import {
useGlobalFilter,
usePagination,
useRowSelect,
useSortBy,
useTable,
} from 'react-table'
const IndeterminateCheckbox = React.forwardRef(
({ indeterminate, ...rest }, ref) => {
const defaultRef = React.useRef()
const resolvedRef = ref || defaultRef
React.useEffect(() => {
resolvedRef.current.indeterminate = indeterminate
}, [resolvedRef, indeterminate])
return (
<>
<Checkbox ref={resolvedRef} {...rest} />
</>
)
}
)
const inputStyle = {
padding: 0,
margin: 0,
border: 0,
background: 'transparent',
}
// Create an editable cell renderer
const EditableCell = ({
cell: { value: initialValue },
row: { index },
column: { id },
updateMyData, // This is a custom function that we supplied to our table instance
}) => {
// We need to keep and update the state of the cell normally
const [value, setValue] = React.useState(initialValue)
const onChange = e => {
setValue(e.target.value)
}
// We'll only update the external data when the input is blurred
const onBlur = () => {
updateMyData(index, id, value)
}
// If the initialValue is changed externall, sync it up with our state
React.useEffect(() => {
setValue(initialValue)
}, [initialValue])
return (
<input
style={inputStyle}
value={value}
onChange={onChange}
onBlur={onBlur}
/>
)
}
EditableCell.propTypes = {
cell: PropTypes.shape({
value: PropTypes.any.isRequired,
}),
row: PropTypes.shape({
index: PropTypes.number.isRequired,
}),
column: PropTypes.shape({
id: PropTypes.number.isRequired,
}),
updateMyData: PropTypes.func.isRequired,
}
// Set our editable cell renderer as the default Cell renderer
const defaultColumn = {
Cell: EditableCell,
}
const EnhancedTable = ({
columns,
data,
setData,
updateMyData,
skipPageReset,
}) => {
const {
getTableProps,
headerGroups,
prepareRow,
page,
gotoPage,
setPageSize,
preGlobalFilteredRows,
setGlobalFilter,
state: { pageIndex, pageSize, selectedRowIds, globalFilter },
} = useTable(
{
columns,
data,
defaultColumn,
autoResetPage: !skipPageReset,
// updateMyData isn't part of the API, but
// anything we put into these options will
// automatically be available on the instance.
// That way we can call this function from our
// cell renderer!
updateMyData,
},
useGlobalFilter,
useSortBy,
usePagination,
useRowSelect,
hooks => {
hooks.allColumns.push(columns => [
// Let's make a column for selection
{
id: 'selection',
// The header can use the table's getToggleAllRowsSelectedProps method
// to render a checkbox. Pagination is a problem since this will select all
// rows even though not all rows are on the current page. The solution should
// be server side pagination. For one, the clients should not download all
// rows in most cases. The client should only download data for the current page.
// In that case, getToggleAllRowsSelectedProps works fine.
Header: ({ getToggleAllRowsSelectedProps }) => (
<div>
<IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />
</div>
),
// The cell can use the individual row's getToggleRowSelectedProps method
// to the render a checkbox
Cell: ({ row }) => (
<div>
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
</div>
),
},
...columns,
])
}
)
const handleChangePage = (event, newPage) => {
gotoPage(newPage)
}
const handleChangeRowsPerPage = event => {
setPageSize(Number(event.target.value))
}
const removeByIndexs = (array, indexs) =>
array.filter((_, i) => !indexs.includes(i))
const deleteUserHandler = event => {
const newData = removeByIndexs(
data,
Object.keys(selectedRowIds).map(x => parseInt(x, 10))
)
setData(newData)
}
const addUserHandler = user => {
const newData = data.concat([user])
setData(newData)
}
// Render the UI for your table
return (
<TableContainer>
<TableToolbar
numSelected={Object.keys(selectedRowIds).length}
deleteUserHandler={deleteUserHandler}
addUserHandler={addUserHandler}
preGlobalFilteredRows={preGlobalFilteredRows}
setGlobalFilter={setGlobalFilter}
globalFilter={globalFilter}
/>
<MaUTable {...getTableProps()}>
<TableHead>
{headerGroups.map(headerGroup => (
<TableRow {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<TableCell
{...(column.id === 'selection'
? column.getHeaderProps()
: column.getHeaderProps(column.getSortByToggleProps()))}
>
{column.render('Header')}
{column.id !== 'selection' ? (
<TableSortLabel
active={column.isSorted}
// react-table has a unsorted state which is not treated here
direction={column.isSortedDesc ? 'desc' : 'asc'}
/>
) : null}
</TableCell>
))}
</TableRow>
))}
</TableHead>
<TableBody>
{page.map((row, i) => {
prepareRow(row)
return (
<TableRow {...row.getRowProps()}>
{row.cells.map(cell => {
return (
<TableCell {...cell.getCellProps()}>
{cell.render('Cell')}
</TableCell>
)
})}
</TableRow>
)
})}
</TableBody>
<TableFooter>
<TableRow>
<TablePagination
rowsPerPageOptions={[
5,
10,
25,
{ label: 'All', value: data.length },
]}
colSpan={3}
count={data.length}
rowsPerPage={pageSize}
page={pageIndex}
SelectProps={{
inputProps: { 'aria-label': 'rows per page' },
native: true,
}}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
ActionsComponent={TablePaginationActions}
/>
</TableRow>
</TableFooter>
</MaUTable>
</TableContainer>
)
}
EnhancedTable.propTypes = {
columns: PropTypes.array.isRequired,
data: PropTypes.array.isRequired,
updateMyData: PropTypes.func.isRequired,
setData: PropTypes.func.isRequired,
skipPageReset: PropTypes.bool.isRequired,
}
export default EnhancedTable

View File

@ -0,0 +1,85 @@
import React from 'react'
import InputBase from '@material-ui/core/InputBase'
import { fade, makeStyles } from '@material-ui/core/styles'
import PropTypes from 'prop-types'
import SearchIcon from '@material-ui/icons/Search'
const useStyles = makeStyles(theme => ({
search: {
position: 'relative',
borderRadius: theme.shape.borderRadius,
backgroundColor: fade(theme.palette.common.white, 0.15),
'&:hover': {
backgroundColor: fade(theme.palette.common.white, 0.25),
},
marginRight: theme.spacing(2),
marginLeft: 0,
width: '100%',
[theme.breakpoints.up('sm')]: {
marginLeft: theme.spacing(3),
width: 'auto',
},
},
searchIcon: {
width: theme.spacing(7),
height: '100%',
position: 'absolute',
pointerEvents: 'none',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
inputRoot: {
color: 'inherit',
},
inputInput: {
padding: theme.spacing(1, 1, 1, 7),
transition: theme.transitions.create('width'),
width: '100%',
[theme.breakpoints.up('md')]: {
width: 200,
},
},
}))
const GlobalFilter = ({
preGlobalFilteredRows,
globalFilter,
setGlobalFilter,
}) => {
const classes = useStyles()
const count = preGlobalFilteredRows.length
// Global filter only works with pagination from the first page.
// This may not be a problem for server side pagination when
// only the current page is downloaded.
return (
<div className={classes.search}>
<div className={classes.searchIcon}>
<SearchIcon />
</div>
<InputBase
value={globalFilter || ''}
onChange={e => {
setGlobalFilter(e.target.value || undefined) // Set undefined to remove the filter entirely
}}
placeholder={`${count} records...`}
classes={{
root: classes.inputRoot,
input: classes.inputInput,
}}
inputProps={{ 'aria-label': 'search' }}
/>
</div>
)
}
GlobalFilter.propTypes = {
preGlobalFilteredRows: PropTypes.array.isRequired,
globalFilter: PropTypes.string.isRequired,
setGlobalFilter: PropTypes.func.isRequired,
}
export default GlobalFilter

View File

@ -0,0 +1,88 @@
import React from 'react'
import FirstPageIcon from '@material-ui/icons/FirstPage'
import IconButton from '@material-ui/core/IconButton'
import KeyboardArrowLeft from '@material-ui/icons/KeyboardArrowLeft'
import KeyboardArrowRight from '@material-ui/icons/KeyboardArrowRight'
import LastPageIcon from '@material-ui/icons/LastPage'
import { makeStyles, useTheme } from '@material-ui/core/styles'
import PropTypes from 'prop-types'
const useStyles = makeStyles(theme => ({
root: {
flexShrink: 0,
marginLeft: theme.spacing(2.5),
},
}))
const TablePaginationActions = props => {
const classes = useStyles()
const theme = useTheme()
const { count, page, rowsPerPage, onChangePage } = props
const handleFirstPageButtonClick = event => {
onChangePage(event, 0)
}
const handleBackButtonClick = event => {
onChangePage(event, page - 1)
}
const handleNextButtonClick = event => {
onChangePage(event, page + 1)
}
const handleLastPageButtonClick = event => {
onChangePage(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1))
}
return (
<div className={classes.root}>
<IconButton
onClick={handleFirstPageButtonClick}
disabled={page === 0}
aria-label="first page"
>
{theme.direction === 'rtl' ? <LastPageIcon /> : <FirstPageIcon />}
</IconButton>
<IconButton
onClick={handleBackButtonClick}
disabled={page === 0}
aria-label="previous page"
>
{theme.direction === 'rtl' ? (
<KeyboardArrowRight />
) : (
<KeyboardArrowLeft />
)}
</IconButton>
<IconButton
onClick={handleNextButtonClick}
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
aria-label="next page"
>
{theme.direction === 'rtl' ? (
<KeyboardArrowLeft />
) : (
<KeyboardArrowRight />
)}
</IconButton>
<IconButton
onClick={handleLastPageButtonClick}
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
aria-label="last page"
>
{theme.direction === 'rtl' ? <FirstPageIcon /> : <LastPageIcon />}
</IconButton>
</div>
)
}
TablePaginationActions.propTypes = {
count: PropTypes.number.isRequired,
onChangePage: PropTypes.func.isRequired,
page: PropTypes.number.isRequired,
rowsPerPage: PropTypes.number.isRequired,
}
export default TablePaginationActions

View File

@ -0,0 +1,91 @@
import React from 'react'
import AddUserDialog from './AddUserDialog'
import clsx from 'clsx'
import DeleteIcon from '@material-ui/icons/Delete'
import GlobalFilter from './GlobalFilter'
import IconButton from '@material-ui/core/IconButton'
import { lighten, makeStyles } from '@material-ui/core/styles'
import PropTypes from 'prop-types'
import Toolbar from '@material-ui/core/Toolbar'
import Typography from '@material-ui/core/Typography'
import Tooltip from '@material-ui/core/Tooltip'
const useToolbarStyles = makeStyles(theme => ({
root: {
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(1),
},
highlight:
theme.palette.type === 'light'
? {
color: theme.palette.secondary.main,
backgroundColor: lighten(theme.palette.secondary.light, 0.85),
}
: {
color: theme.palette.text.primary,
backgroundColor: theme.palette.secondary.dark,
},
title: {
flex: '1 1 100%',
},
}))
const TableToolbar = props => {
const classes = useToolbarStyles()
const {
numSelected,
addUserHandler,
deleteUserHandler,
preGlobalFilteredRows,
setGlobalFilter,
globalFilter,
} = props
return (
<Toolbar
className={clsx(classes.root, {
[classes.highlight]: numSelected > 0,
})}
>
<AddUserDialog addUserHandler={addUserHandler} />
{numSelected > 0 ? (
<Typography
className={classes.title}
color="inherit"
variant="subtitle1"
>
{numSelected} selected
</Typography>
) : (
<Typography className={classes.title} variant="h6" id="tableTitle">
Users
</Typography>
)}
{numSelected > 0 ? (
<Tooltip title="Delete">
<IconButton aria-label="delete" onClick={deleteUserHandler}>
<DeleteIcon />
</IconButton>
</Tooltip>
) : (
<GlobalFilter
preGlobalFilteredRows={preGlobalFilteredRows}
globalFilter={globalFilter}
setGlobalFilter={setGlobalFilter}
/>
)}
</Toolbar>
)
}
TableToolbar.propTypes = {
numSelected: PropTypes.number.isRequired,
addUserHandler: PropTypes.func.isRequired,
deleteUserHandler: PropTypes.func.isRequired,
setGlobalFilter: PropTypes.func.isRequired,
preGlobalFilteredRows: PropTypes.array.isRequired,
globalFilter: PropTypes.string.isRequired,
}
export default TableToolbar

View File

@ -0,0 +1,13 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}

View File

@ -0,0 +1,6 @@
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
ReactDOM.render(<App />, document.getElementById('root'))

View File

@ -0,0 +1,40 @@
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 default function makeData(...lens) {
const makeDataLevel = (depth = 0) => {
const len = lens[depth]
return range(len).map(d => {
return {
...newPerson(),
subRows: lens[depth + 1] ? makeDataLevel(depth + 1) : undefined,
}
})
}
return makeDataLevel()
}

File diff suppressed because it is too large Load Diff