"use client"; import clsx from "clsx"; import { Children, useState } from "react"; import reset from "../../styles/reset/reset.module.css"; import { Badge } from "../Badge"; import { Checkbox } from "../Checkbox"; import { Scroller } from "../Scroller"; import styles from "./Table.module.css"; interface Cell extends React.FC<{ value: any; // FIXME }> {} type Column = { Header: string; accessor: string | null; ellipsis?: boolean; expandable?: boolean; fixedWidth?: number; align?: "right" | "center"; columnClassName?: string; /** * @example * ```tsx * Cell: ({ value }) => { * if (!value) return '' * return '$' + value * } * ``` */ Cell?: Cell; }; type Data = any; type HeaderActionParams = { idsChecked: string[]; disabled: boolean }; type RowActionParams = { row: any; rowIdx: number }; interface Props { columns?: Column[]; data?: Data[]; caption?: string; overflow?: number; header?: boolean; sticky?: boolean; sortable?: boolean; defaultRows?: number; selectable?: boolean; fixed?: boolean; headerActions?: (params: HeaderActionParams) => JSX.Element; rowActions?: (params: RowActionParams) => JSX.Element; width?: React.HTMLAttributes["style"]["width"]; height?: React.HTMLAttributes["style"]["height"]; empty?: JSX.Element; } const Table: React.ComponentType> = ({ selectable, columns = [], data = [], caption = "A basic table", overflow, header = true, headerActions, rowActions, width = "100%", height = "100%", defaultRows, sticky, empty, fixed, children, }) => { const [idsChecked, setIdsChecked] = useState([]); // console.log(Children.count(children)); // 1 return (
{!!Children.count(children) && (
{children}
)}
{selectable && } {columns.map((col, i) => { return ; })} {selectable && } { // Generate Header Checkbox selectable && ( ) } {columns.map((column, i) => { const { Header, accessor, fixedWidth, align, columnClassName, } = column; // Generate column headers return ( ); })} { // Generate Header Overflow menu selectable && ( ) } {data?.map((row, rowIdx) => { // Generate each row return ( { // Generate Row item Checkbox selectable && ( ) } {columns.map((column, colIdx) => { const { accessor, Cell, ellipsis, align, columnClassName, } = column; // For each row, // Generate each column value, by columns.accessor const cn = clsx( { [styles.ellipsisCell]: ellipsis, [styles.center]: align === "center", [styles.right]: align === "right", }, columnClassName, ); const key = `${accessor}${colIdx}`; if (Cell) { // accessor may be null if we want to use the `Cell` // property — a React FC — to do some transformations // on the root data object. // ex. The root object might have related models. // And the column value that should be displayed // may need to derive data from various related models if (accessor === null) { return ( ); } return ( ); } return ( ); })} { // Generate Row item Overflow menu selectable && ( ) } ); })}
{caption}
{ if (e.target.checked) { setIdsChecked(data?.map((e) => e.id)); } else { setIdsChecked([]); } }} />
{Header}
{!!idsChecked.length && ( {idsChecked.length} )} {typeof headerActions === "function" && headerActions({ idsChecked, disabled: idsChecked.length === 0, })}
{ if (e.target.checked) { setIdsChecked((ids) => [...ids, row.id]); } else { setIdsChecked((ids) => ids.filter((id) => id !== row.id), ); } }} />
{row[accessor]}
{typeof rowActions === "function" && rowActions({ row, rowIdx, })}
{!data || data?.length === 0 ? ( empty ? (
{empty}
) : (
); }; export default Table;