I have a material-ui Table and I'm adding multi-select capability to it. My requirements are as follows.
Checkboxes are all initially hidden. - DONE
When hovering on a row its checkbox appears. DONE
Once one Checkbox is checked then all Checkbox elements on other rows become constantly visible.
I have the first two requirements done but I'm struggling with the final one.
How do I get all checkboxes to be visible (by changing opacity) once any one of them becomes checked ?
This is where I've got to so far :
import React from "react";
import PropTypes from "prop-types";
import { makeStyles } from "#material-ui/core/styles";
import Table from "#material-ui/core/Table";
import TableBody from "#material-ui/core/TableBody";
import TableCell from "#material-ui/core/TableCell";
import TableContainer from "#material-ui/core/TableContainer";
import TableHead from "#material-ui/core/TableHead";
import TableRow from "#material-ui/core/TableRow";
import Paper from "#material-ui/core/Paper";
import Checkbox from "#material-ui/core/Checkbox";
const useStyles = makeStyles({
rowIconStyle: {
minWidth: 50,
minHeight: 50
},
tableRowStyle: {
cursor: "pointer",
"&:hover": {
backgroundColor: "darkGrey"
}
},
rowSelectionCheckboxStyle: {
//opacity: "calc(var(--oneRowSelected))",
opacity: 0,
"$tableRowStyle:hover &": {
opacity: 1
}
}
});
export default function MyTableComponent(props) {
const styles = useStyles();
const DEFAULT_TABLE_ROW_ICON_COLOR = "grey";
return (
<TableContainer component={Paper}>
<Table aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>
<Checkbox className={styles.rowSelectionCheckboxStyle} />
</TableCell>
<TableCell>Icon</TableCell>
<TableCell>Name</TableCell>
</TableRow>
</TableHead>
<TableBody>
{props.tableRowsData.map(row => {
const RowIcon =
row.icon && row.icon.iconElement
? row.icon.iconElement
: () => <div />;
let iconElement = (
<RowIcon
className={styles.rowIconStyle}
style={{
color:
row.icon && row.icon.color
? row.icon.color
: DEFAULT_TABLE_ROW_ICON_COLOR
}}
/>
);
return (
<TableRow key={row.name} className={styles.tableRowStyle}>
<TableCell>
<Checkbox className={styles.rowSelectionCheckboxStyle} />
</TableCell>
<TableCell>{iconElement}</TableCell>
<TableCell>{row.projectName}</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</TableContainer>
);
}
MyTableComponent.propTypes = {
tableRowsData: PropTypes.array
};
Have a value and an onChange in your Checkbox. Maintain a state which represents the selected checkboxes and update it upon onChange. Check the checkboxes array and only attach the class styles.rowSelectionCheckboxStyle if any one checkbox is checked.
Working copy of your code is here
export default function MyTableComponent(props) {
const [checkedRows, setCheckedRows] = useState({});
const styles = useStyles();
const DEFAULT_TABLE_ROW_ICON_COLOR = "grey";
const anyChecked = () => {
let anyRowChecked = false;
for (let key in checkedRows) {
if (checkedRows[key]) {
anyRowChecked = true;
}
}
return anyRowChecked;
};
const checked = (checked, index) => {
setCheckedRows(prev => ({ ...prev, [index]: checked }));
};
...
...
return (
<TableRow key={row.name} className={styles.tableRowStyle}>
<TableCell>
<Checkbox
checked={checkedRows[index]}
onChange={e => checked(e.target.checked, index)}
className={
!anyChecked() && styles.rowSelectionCheckboxStyle
}
/>
</TableCell>
<TableCell>{iconElement}</TableCell>
<TableCell>
{checkedRows[index] ? "True" : "False"} {row.projectName}
</TableCell>
</TableRow>
);
})}
...
Related
Okay so I have a really strange error in my react application.
Basically I have a function that handles an input change and changes the state from the parent component.
import React from "react";
import PaginationExtended from "../PaginationExtended/PaginationExtended";
import { ScreenContext } from "../../helpers/context";
import {
Paper,
TableCell,
TableContainer,
Table,
TableBody,
TableHead,
TableRow,
Checkbox,
TextField,
} from "#material-ui/core";
import EnhancedTableToolbar from "../EnhancedToolBar/EnhancedToolBar";
import uuid from "react-uuid";
import findWithAttr from "../../helpers/findAttr";
import objectInArray from "../../helpers/objectInArray";
import ItemTableRow from "./ItemTableRow/ItemTableRow";
const ItemTable = (props) => {
const screen = React.useContext(ScreenContext);
const handleCheckboxClick = (e) => {
if (e.target.checked) {
props.setDynamicRows((prevState) => {
const newTableData = [...prevState];
console.log(newTableData);
const rowIndex = findWithAttr(props.rows, "id", parseInt(e.target.id));
const newRow = {};
props.headings.forEach((heading) => {
newRow[heading.text.toLowerCase()] =
props.rows[rowIndex][heading.default];
});
newRow.id = e.target.id;
newRow.type = "accepted";
newRow.files = [];
newRow.category = props.title;
newTableData.push(newRow);
return newTableData;
});
} else {
props.setDynamicRows((prevState) => {
const newTableData = [...prevState];
console.log(newTableData);
const rowIndex = findWithAttr(
newTableData,
"id",
parseInt(e.target.id)
);
newTableData.splice(rowIndex, 1);
return newTableData;
});
}
};
const handleInputChange = () => {
console.log(1);
props.setDynamicRows((prevState) => {
const newTableData = [...prevState];
console.log(newTableData);
const rowIndex = findWithAttr(newTableData, "id", props.row.id);
newTableData[rowIndex][e.target.name] = e.target.value;
return newTableData;
});
};
return (
<Paper className={`${props.className}`}>
<EnhancedTableToolbar
screen={screen}
title={props.title}
// record={props.rows}
// setRows={setRows}
/>
<TableContainer>
<Table aria-label="simple table">
<TableHead>
<TableRow>
{props.hasCheckbox && <TableCell padding="checkbox" />}
{props.headings.map((heading) => {
return (
<TableCell className={"text-nowrap"} align="right">
{heading.text}
</TableCell>
);
})}
</TableRow>
</TableHead>
<TableBody>
{props.rows.map((row, index) => {
if (!props.inputTable) {
return (
<ItemTableRow
title={props.title}
headings={props.headings}
handleCheckboxClick={handleCheckboxClick}
dynamicRows={props.dynamicRows}
index={index}
row={row}
hasCheckbox={props.hasCheckbox}
setDynamicRows={props.setDynamicRows}
/>
);
} else {
if (row.type === "accepted" && row.category === props.title) {
return (
<ItemTableRow
title={props.title}
headings={props.headings}
handleCheckboxClick={handleCheckboxClick}
dynamicRows={props.dynamicRows}
index={index}
row={row}
hasCheckbox={props.hasCheckbox}
handleInputChange={handleInputChange}
/>
);
}
}
})}
</TableBody>
</Table>
</TableContainer>
{props.hasPagination && (
<PaginationExtended
recordsPerPage={rowsPerPage}
className={"p-3 justify-content-end"}
totalRecords={rows.length}
paginate={handleChangePage}
currentPage={page}
shape={"round"}
/>
)}
</Paper>
);
};
export default ItemTable;
This function is called from a child component of the component at the top.
import React from "react";
import { TableCell, TableRow, Checkbox, TextField } from "#material-ui/core";
import objectInArray from "../../../helpers/objectInArray";
const ItemTableRow = (props) => {
return (
<TableRow key={props.index}>
{props.hasCheckbox && (
<TableCell padding="checkbox">
<Checkbox
id={props.row.id}
checked={objectInArray(
props.dynamicRows,
"id",
props.row.id.toString()
)}
onClick={props.handleCheckboxClick}
// inputProps={{
// "aria-labelledby": `${props.title}-${index}`,
// }}
/>
</TableCell>
)}
{props.headings.map((heading) => {
return (
<TableCell
className={"text-nowrap"}
id={`${props.title}-${props.index}`}
align="right"
>
{heading.isTextInput ? (
<TextField
onChange={props.handleInputChange}
id={`${props.title}-${heading.text}-${props.row.id}`}
type={heading.inputType}
size={"small"}
variant="outlined"
inputProps={{ min: 0 }}
notched={false}
InputLabelProps={{ shrink: false }}
className={`minInputWidth`}
InputProps={{
classes: { input: "py-2 customize-inputField" },
}}
name={heading.text.toLowerCase()}
placeholder={heading.text}
/>
) : (
<p>{props.row[heading.default]}</p>
)}
</TableCell>
);
})}
</TableRow>
);
};
export default ItemTableRow;
When I trigger this event the following error appears in the console.
Uncaught TypeError: props.setDynamicRows is not a function
The curious thing about this is that the handleCheckboxClick function does not throw any error and is also called called from the child component. I have tried reestructuring the components and functions but nothing works.
If someone knows what is happening I would really appreciate the help, thanks.
I'm working a project that requires uploading multiple files to firebase using React. Currently, I can loop over the data inside of "FormData" however, I want to keep the data in-sync (i.e if a user uploads 3 files the expectation is that the file uploaded to firebase storage will stay consistent with the user's info - First_name/Last_name)
Here's a quick look at what my current FormData Output looks like:
The Code I am currently using looks like this (There's ALOT of trial and error here..):
import React, { useState } from "react";
import Confetti from "react-confetti";
import Swal from "sweetalert2";
import { makeStyles } from "#material-ui/core/styles";
import { Link } from "react-router-dom";
import { useData } from "./DataContext";
import { MainContainer } from "./components/MainContainer";
import { PrimaryButton } from "./components/PrimaryButton";
import Table from "#material-ui/core/Table";
import TableBody from "#material-ui/core/TableBody";
import TableCell from "#material-ui/core/TableCell";
import TableContainer from "#material-ui/core/TableContainer";
import TableHead from "#material-ui/core/TableHead";
import TableRow from "#material-ui/core/TableRow";
import Paper from "#material-ui/core/Paper";
import Typography from "#material-ui/core/Typography";
import List from "#material-ui/core/List";
import ListItem from "#material-ui/core/ListItem";
import ListItemIcon from "#material-ui/core/ListItemIcon";
import ListItemText from "#material-ui/core/ListItemText";
import InsertDriveFile from "#material-ui/icons/InsertDriveFile";
import { db } from './localfirebaseconfig';
/* Firebase Imports */
import 'firebase/firestore';
import { useFirestoreDocData, useFirestore } from 'reactfire';
const useStyles = makeStyles({
root: {
marginBottom: "30px",
},
table: {
marginBottom: "30px",
},
});
export const Result = () => {
const [success, setSuccess] = useState(false);
const styles = useStyles();
const { data } = useData();
const entries = Object.entries(data).filter((entry) => entry[0] !== "files");
const { files } = data;
const onSubmit = async () => {
const formData = new FormData();
if (data.files) {
data.files.forEach((file) => {
formData.append("files", file, file.name);
});
}
entries.forEach((entry) => {
formData.append(entry[0], entry[1]);
});
let formEntries = 0;
for (let pair of formData.entries()){
console.log(pair)
}
// for (let i = 0; i < formEntries; i++){
// for(let data of formData.entries()){
// let test = {
// firstName: data[0] == 'firstName',
// lastName: data[0] == 'lastName',
// }
// console.log(data)
// }
// }
const form_stuff = new Map(formData.entries())
// db.collection('test').doc().set({testing:'THis is a test'})
// if (true) {
// Swal.fire("Great job!", "You've passed the challenge!", "success");
// setSuccess(true);
// }
};
// if (true) {
// return <Confetti />;
// }
return (
<>
<MainContainer>
<Typography component="h2" variant="h5">
📋 Form Values
</Typography>
<TableContainer className={styles.root} component={Paper}>
<Table className={styles.table} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Field</TableCell>
<TableCell align="right">Value</TableCell>
</TableRow>
</TableHead>
<TableBody>
{entries.map((entry) => (
<TableRow key={entry[0]}>
<TableCell component="th" scope="row">
{entry[0]}
</TableCell>
<TableCell align="right">{entry[1].toString()}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
{files && (
<>
<Typography component="h2" variant="h5">
📦 Files
</Typography>
<List>
{files.map((f, index) => (
<ListItem key={index}>
<ListItemIcon>
<InsertDriveFile />
</ListItemIcon>
<ListItemText primary={f.name} secondary={f.size} />
</ListItem>
))}
</List>
</>
)}
<PrimaryButton onClick={onSubmit}>Submit</PrimaryButton>
<Link to="/">Start over</Link>
</MainContainer>
</>
);
};
If it helps, here's the code inside of a git repo - https://github.com/Double-Edge-Software/ultimate-react-hook-form-form
Along with a stack blitz -- https://stackblitz.com/github/Double-Edge-Software/ultimate-react-hook-form-form
Any help and/or nudges in the right direction would help alot!
Thanks
It looks like FormData.entries() gives you an array containing only an Iterator of length 0.
However, you can build an Array from the Iterator using Array.from().
I was able to map over the FormData entries like so:
let form = document.querySelector('#myform');
let formData = new FormData(form);
Array.from(formData.entries())
.map((entry, index) => {
console.log(`${index}: ${entry}`)
});
I have an upload file component, delete file component and files table component(presents the existing files in the system using axios) in the same page:
filesPage.js
import React from 'react';
import UploadFile from '../components/UploadFile'
import DeleteFile from '../components/DeleteFile'
import FilesTable from '../components/FilesTable'
function UploadFiles() {
return (
<div className="filesPage">
<UploadFile/>
<DeleteFile/>
<FilesTable/>
</div>
)
}
export default UploadFiles;
Now I want every time I upload new file or delete one, the files table will be updated which means after the axios post/delete, I need to rerender the files table component and do axios get again to get the active files.
Someone can help?
FilesTable.js
import React, {useState, useEffect} from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Paper from '#material-ui/core/Paper';
import Table from '#material-ui/core/Table';
import TableBody from '#material-ui/core/TableBody';
import TableCell from '#material-ui/core/TableCell';
import TableContainer from '#material-ui/core/TableContainer';
import TableHead from '#material-ui/core/TableHead';
import TablePagination from '#material-ui/core/TablePagination';
import TableRow from '#material-ui/core/TableRow';
import axios from 'axios';
function FilesTable() {
const [tfaArray, setTfaArray] = useState([]);
useEffect(() => {
axios.get("api/tfa").then((res) => setTfaArray(res.data)).catch((err) => console.log(err));
}, [])
const columns = [
{id: 'fileId', label: '#', minWidth: 100},
{id: 'name', label: 'name', minWidth: 100},
{id: 'date', label: 'upload date', minWidth: 100}
];
const rows = tfaArray.map((tfa, index) => ({fileId: (index + 1), name: tfa.fileName, date: tfa.dateTime.slice(0,24)}) )
const useStyles = makeStyles({
root: {
width: '50%',
position: 'absolute',
right: '10%',
top: '15%',
},
container: {
maxHeight: 322
},
headerCell: {
background: '#F5F5F5',
fontSize: '16px',
zIndex: '0'
}
});
const classes = useStyles();
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(5);
const handleChangePage = (event, newPage) => {
setPage(newPage);
};
const handleChangeRowsPerPage = (event) => {
setRowsPerPage(+event.target.value);
setPage(0);
};
return (
<>
<Paper className={classes.root}>
<TableContainer className={classes.container}>
<Table stickyHeader aria-label="sticky table">
<TableHead>
<TableRow>
{columns.map((column) => (
<TableCell className={classes.headerCell}
key={column.id}
style={{ minWidth: column.minWidth }}>
{column.label}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{rows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((row, index) => {
return (
<TableRow hover role="checkbox" tabIndex={-1} key={index}>
{columns.map((column) => {
const value = row[column.id];
return (
<TableCell key={column.id}>
{value}
</TableCell>
);
})}
</TableRow>
);
})}
</TableBody>
</Table>
</TableContainer>
<TablePagination
rowsPerPageOptions={[5, 10, 15]}
component="div"
count={rows.length}
rowsPerPage={rowsPerPage}
page={page}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
/>
</Paper>
</>
)
}
export default FilesTable;
Typically with React you do this by lifting state up as described in this React documentation.
In this case, you'd lift the state to the parent of these components, and have the FilesTable receive the list of files as a prop. (Props are basically component state managed by the parent rather than by the component itself.) Similarly the DeleteFile component would receive the function to call to delete a file, the UploadFile component would receive the function to use to add a file, etc.
Here's a simplified example:
const {useState} = React;
const Parent = () => {
const [files, setFiles] = useState([]);
const addFile = (file) => {
setFiles(files => [...files, file]);
};
const removeFile = (file) => {
setFiles(files => files.filter(f => f !== file));
};
return (
<div>
<FilesTable files={files} removeFile={removeFile} />
<UploadFile addFile={addFile} />
</div>
);
};
const FilesTable = ({files, removeFile}) => {
return (
<React.Fragment>
<div>{files.length === 1 ? "One file:" : `${files.length} files:`}</div>
<ul className="files-table">
{files.map(file => (
<li>
<span>{file}</span>
<span className="remove-file" onClick={() => removeFile(file)}>[X]</span>
</li>
))}
</ul>
</React.Fragment>
);
};
const UploadFile = ({addFile}) => {
const [file, setFile] = useState("");
const onClick = () => {
addFile(file);
setFile("");
};
return (
<div>
<input type="text" value={file} onChange={(e) => setFile(e.target.value)} />
<input type="button" value="Add" disabled={!file} onClick={onClick} />
</div>
);
};
ReactDOM.render(<Parent />, document.getElementById("root"));
ul.files-table {
list-style-type: none;
}
.remove-file {
margin-left: 0.5rem;
cursor: pointer;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
I am trying to create a Checkbox to display and hide my React Table with some data in it. I have only used classes and am new to using Functions and as a result am struggling to implement a way to create a checkbox that can hide my React Table or a column.
import "react-table/react-table.css";
import React, { Component, useState, useEffect } from "react";
function dataquery() {
return fetch("www.website.com").then(response =>
response.json()
);
}
function Offence() {
const [count, setCount] = useState([]);
useEffect(() => {
dataquery().then(headlines => {
setCount(headlines);
});
}, []);
//event.preventDefault();
console.log(count.offences);
let data = [{}];
if (typeof count.offences !== "undefined" ) {
let newdata = count.offences.map(count => data.push({ name: count }));
// console.log("???");
}
console.log(typeof count.offence);
const columns = [
{
Header: "Name",
accessor: "name",
},
];
// trying to hide this react table or just hide the column
return <ReactTable data={data} columns={columns} filterable />;
}
export default Offence;
I am exporting this function into another file in which I render 'Offence'.
The fetch website is not the actual website as it needs a private login to work, so I replaced it with this placeholder for the purpose of this.
Thank you.
You can easily add an useState hook, which stores a boolean to show/not show the table. Then toggle this state when changing a checkbox. For example:
function Offence() {
// ... your component code
const [showTable, setShowTable] = useState(true);
// output
return (
<>
<input
type="checkbox"
checked={showTable}
onChange={() => { setShowTable(p => !p); }}
/>
{showTable ? <ReactTable ... /> : null}
</>
);
}
I have only used classes and am new to using Functions
In such a situation, I highly recommend to use materialui components. It would make your life much easier because you need not to step into gory details of styling anymore if you do not want to.
Below I roughly drafted a component which contains a table and a list of checkboxes for switching hide/show columns.
Hope it helps :)
import React, { useState, useEffect } from 'react'
import Grid from '#material-ui/core/Grid';
import Card from '#material-ui/core/Card';
import CardHeader from '#material-ui/core/CardHeader';
import CardContent from '#material-ui/core/CardContent';
import Table from '#material-ui/core/Table';
import TableBody from '#material-ui/core/TableBody';
import TableCell from '#material-ui/core/TableCell';
import TableHead from '#material-ui/core/TableHead';
import TableRow from '#material-ui/core/TableRow';
import FormControl from '#material-ui/core/FormControl';
import FormGroup from '#material-ui/core/FormGroup';
import FormControlLabel from '#material-ui/core/FormControlLabel'
import Checkbox from '#material-ui/core/Checkbox';
function App() {
const [showName, setshowName] = useState(true);
const [showQty, setshowQty] = useState(true);
const [showPrice, setshowPrice] = useState(true);
const dummydata = [{ name: "apple", qty: 12, price: 3.3 }, { name: "orange", qty: 3, price: 1.5 }, { name: "grape", qty: 10, price: 4.3 }]
return (
<Grid
container
direction="row"
justify="space-around"
alignItems="center"
>
<Grid item xs={12} sm={5}>
<Card>
<Table>
<TableHead>
<TableRow>
{showName ? <TableCell>Name</TableCell> : ""}
{showQty ? <TableCell >Qty.</TableCell> : ""}
{showPrice ? <TableCell >Price</TableCell> : ""}
</TableRow>
</TableHead>
<TableBody>
{dummydata.map(item => (
<TableRow>
{showName ? <TableCell component="th" scope="row" padding="none">
{item.name}
</TableCell> : ""}
{showQty ? <TableCell>{item.qty}</TableCell> : ""}
{showPrice ? <TableCell>{item.price}</TableCell> : ""}
</TableRow>
))}
</TableBody>
</Table>
</Card>
</Grid>
<Grid item xs={12} sm={5}>
<Card>
<CardHeader
title="Hide any column?"
/>
<CardContent>
<FormControl style={{ margin: 4 }}>
<FormGroup>
<FormControlLabel
control={
<Checkbox onChange={(e, checked) => setshowName(checked)} checked={showName} />
}
label="Hide Name"
/>
<FormControlLabel
control={
<Checkbox onChange={(e, checked) => setshowQty(checked)} checked={showQty} />
}
label="Hide Quantity"
/>
<FormControlLabel
control={
<Checkbox onChange={(e, checked) => setshowPrice(checked)} checked={showPrice} />
}
label="Hide Price"
/>
</FormGroup>
</FormControl>
</CardContent>
</Card>
</Grid>
</Grid>
);
}
export default App;
I have an app running at this URL:
https://sentify-kth.herokuapp.com/my-searches
As you can see, there is a circular loading animation in the table. I want to place this animation in the middle of the table body, like this (imagine that it's in the center and not slightly to the right):
I can't get this to work. My attempt has been to style the element with class=progress. I've tried width:100%; margin:auto. I've also tried text-align:center. That didn't work either. I don't know what else to try.
How can I center the circular animation?
The React code:
render() {
const { classes } = this.props;
const { data, selected, rowsPerPage, page } = this.state;
let tableBody;
let emptyRows;
switch(this.state.status){
case "LOADING":
tableBody = <CircularIndeterminate/>;
emptyRows = undefined;
break;
case "LOADED":
tableBody = <CircularIndeterminate/>;
break;
}
return (
<Paper className={classes.root}>
<EnhancedTableToolbar
numSelected={selected.length}
handleClickDeleteBtn={this.handleClickDeleteBtn}
open={this.state.open}
handleCloseModal={this.handleCloseModal}
handleConfirm={this.handleConfirm}
handleCancel={this.handleCancel}
/>
<div className={classes.tableWrapper}>
<Table className={classes.table}>
<EnhancedTableHead
numSelected={selected.length}
onSelectAllClick={this.handleSelectAllClick}
rowCount={data === null || data === undefined ? -1 : (data.length || -1)}
/>
<TableBody>
{tableBody}
{emptyRows > 0 && (
<TableRow style={{ height: 49 * emptyRows }}>
<TableCell colSpan={6} />
</TableRow>
)}
</TableBody>
</Table>
</div>
<TablePagination
component="div"
count={data === null || data === undefined ? 0 : data.length || 0}
rowsPerPage={rowsPerPage}
page={page}
backIconButtonProps={{
'aria-label': 'Previous Page',
}}
nextIconButtonProps={{
'aria-label': 'Next Page',
}}
onChangePage={this.handleChangePage}
onChangeRowsPerPage={this.handleChangeRowsPerPage}
/>
</Paper>
);
}
}
CircularIndeterminate.js:
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from 'material-ui/styles';
import { CircularProgress } from 'material-ui/Progress';
const styles = theme => ({
progress: {
margin: theme.spacing.unit * 2,
},
});
function CircularIndeterminate(props) {
const { classes } = props;
return (
<div className="progress">
<CircularProgress className={classes.progress} size={100} thickness={4}/>
</div>
);
}
CircularIndeterminate.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(CircularIndeterminate);
Here's how I solved it (there was an answer saying pretty much the same thing, but it was removed for an unknown reason):
Put the circle in a tr and td element
Set colspan=6 on the td element
Set text-align:center for the .progress element.
Code:
tableBody = (
<tr>
<td colspan="6">
<CircularIndeterminate/>
</td>
</tr>
);
css:
.progress{
text-align:center
}