Source

Utils/DataDisplay/VirtualizedTable.js

import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import clsx from "clsx";
import TextWithHoverTooltip from "./TextWithHoverTooltip";
import { makeStyles } from '@material-ui/core/styles';
import { AutoSizer, Column, Table } from 'react-virtualized';

/**
 * <h3>Overview</h3>
 * Estimates height of the {@link VirtualizedTable} for given data.
 *
 * @function
 * @category Utils
 * @subcategory Functions
 * @param {Array} data - An array of objects that is going to be displayed in {@link VirtualizedTable}.
 * @param {number} [rowHeight = 48] - Height of a row from the table.
 * @returns {number} An estimated height of the table.
 */
export const estimateTableHeight = (data, rowHeight = 48) => {
    return (data.length + 1) * rowHeight;
};

const tableStyles = makeStyles(theme => ({
    table: {
        '& .ReactVirtualized__Grid__innerScrollContainer': {
            background: theme.palette.background.main1,
            color: theme.palette.text.main1,
        },
        '& .ReactVirtualized__Table__headerRow': {
            backgroundColor: theme.palette.background.subLight,
            color: theme.palette.text.special2
        }
    },
    tableRow: {
        borderBottom: "1px solid rgba(0, 0, 0, 0.12)",
        display: "flex",
    },
    tableColumn: {
        alignItems: 'center',
        display: 'flex',
        flexGrow: "1 !important",
        padding: "8px 16px",
        width: "100%"
    },
    headerColumn: {
        overflow: "hidden"
    },
    headerCell: {
        ...theme.typography.subheader,
    },
    textCell: {
        cursor: "default"
    },
}), {name: "virtualized-table"});

/**
 * <h3>Overview</h3>
 * A Table component wrapped around in AutoSizer from react-virtualized library with custom styling.
 * There are default <code>cellRenderer</code> and <code>headerRenderer</code> functions in this component.
 * However, you can forward your own functions to replace them.
 * For full documentation check out this react-virtualized docs on
 * <a href="https://github.com/bvaughn/react-virtualized/blob/master/docs/Table.md">Table</a>,
 * <a href="https://github.com/bvaughn/react-virtualized/blob/master/docs/AutoSizer.md">AutoSizer</a> and
 * <a href="https://github.com/bvaughn/react-virtualized/blob/master/docs/Column.md">Column</a>.
 *
 * @constructor
 * @category Utils
 * @subcategory Data Display
 * @param {Object} props - Any other props will be forwarded to the Table component.
 * @param {Object} [props.classes] - Override or extend the styles applied to the component.
 * @param {Object[]} props.columns - A data set that is going to be displayed in VirtualizedTable.
 * @returns {React.ReactElement}
 */
function VirtualizedTable(props) {
    const { cellRenderer, classes, columns, rowHeight, headerRender, headerHeight, ...tableProps } = props;
    const tableClasses = {...tableStyles(), ...classes};

    /**
     * <h3>Overview</h3>
     * Default <code>cellRenderer</code> for <code>VirtualizedTable</code>.
     * It renders a {@link TextWithHoverTooltip}.
     * <br>
     * For full documentation check out react-virtualized docs on
     * <a href="https://github.com/bvaughn/react-virtualized/blob/master/docs/Column.md#cellrenderer">cellRenderer</a>
     *
     * @param cellData {*} - The content of a table cell.
     * @param dataKey {string} - The key property of a table cell.
     * @returns {React.ReactElement}
     */
    const cellRendererDefault = ({ cellData, dataKey }) => {
        return (
            <Fragment>
                {cellData &&
                    <TextWithHoverTooltip
                        roundNumbers={false}
                        text={cellData}
                        TooltipProps={{
                            id: dataKey
                        }}
                        TypographyProps={{
                            className: tableClasses.textCell
                        }}
                    />
                }
            </Fragment>
        );
    };

    /**
     * <h3>Overview</h3>
     * Default <code>headerRenderer</code> for <code>VirtualizedTable</code>.
     * It renders a {@link TextWithHoverTooltip}.
     * <br>
     * For full documentation check out react-virtualized docs on
     * <a href="https://github.com/bvaughn/react-virtualized/blob/master/docs/Column.md#headerrenderer">headerRenderer</a>
     *
     * @param {*} label - The content of a header cell.
     * @returns {React.ReactElement}
     */
    const headerRendererDefault = ({ label }) => {
        return (
            <Fragment>
                {label &&
                    <TextWithHoverTooltip
                        text={label}
                        TypographyProps={{
                            className: clsx(tableClasses.textCell, tableClasses.headerCell)
                        }}
                    />
                }
            </Fragment>
        );
    };

    return (
        <AutoSizer>
            {({ height, width }) => (
                <Table
                    className={tableClasses.table}
                    headerHeight={headerHeight}
                    headerClassName={clsx(tableClasses.tableColumn, tableClasses.headerColumn)}
                    height={height}
                    gridStyle={{direction: 'inherit'}}
                    rowClassName={tableClasses.tableRow}
                    rowHeight={rowHeight}
                    width={width}
                    {...tableProps}
                >
                    {columns.map(({ dataKey, ...other }) => {
                        return (
                            <Column
                                cellRenderer={
                                    typeof cellRenderer === "function" ? cellRenderer : cellRendererDefault
                                }
                                className={tableClasses.tableColumn}
                                dataKey={dataKey}
                                headerRenderer={
                                    typeof headerRender === "function" ? headerRender : headerRendererDefault
                                }
                                key={dataKey}
                                {...other}
                            />
                        );
                    })}
                </Table>
            )}
        </AutoSizer>
    );
}

VirtualizedTable.propTypes = {
    cellRenderer: PropTypes.func,
    classes: PropTypes.object,
    columns: PropTypes.arrayOf(
        PropTypes.shape({
            dataKey: PropTypes.string.isRequired,
            label: PropTypes.string.isRequired,
            width: PropTypes.number.isRequired,
        }),
    ).isRequired,
    headerHeight: PropTypes.number,
    headerRender: PropTypes.func,
    onRowClick: PropTypes.func,
    rowCount: PropTypes.number.isRequired,
    rowGetter: PropTypes.func.isRequired,
    rowHeight: PropTypes.oneOfType([
        PropTypes.number,
        PropTypes.func
    ]).isRequired,
    rowStyle: PropTypes.oneOfType([
        PropTypes.object,
        PropTypes.func
    ])
};

VirtualizedTable.defaultProps = {
    headerHeight: 48,
    rowHeight: 48,
};

export default VirtualizedTable;