UNPKG

@sinchsmb/ui-kit

Version:

UI kit for SinchSMB frontend

318 lines (317 loc) 9.66 kB
import { ReactNode } from 'react'; import { CommonProps } from '../../types'; import { TableColumnVisibility, TableSelection, TableSort } from './types'; /** Props for the {@link Table} component */ export type TableProps<C extends string, D extends object> = CommonProps & { /** The data to display in the table */ rows: D[]; /** Function that should return unique key for given row */ rowIdProvider: (row: D) => string; /** List of columns to display in the table */ columns: TableColumnVisibility<C>[] | C[]; /** Count of all rows that can be rendered on table */ totalRows: number; /** Current table selection */ selection?: TableSelection; /** Function that should be called when table selection is changed */ onSelectionChanged?: (selection: TableSelection) => void; /** Current table sort */ sort?: TableSort<C>; /** Function that should be called when table sort is changed */ onSortChanged?: (sort: TableSort<C>) => void; /** If `true` than loader indicator will be shown */ loading?: boolean; /** Limit the number of table selections */ rowSelectionIncludeLimit?: number; /** * If `true` than user can use row actions. * * @default true */ rowActionsEnabled?: boolean; /** * If `true`, the "actions" and "selection" columns are always visible */ stickyColumns?: boolean; children: ReactNode; } & ({ /** * If `true` than user can select rows. * * @default true */ rowSelectionEnabled: true; /** Item name to show in the selection banner */ rowSelectionName: string; } | { rowSelectionEnabled?: false; rowSelectionName?: string; }); /** * Component is used for show data in table view. * * It supports flexible data cell rendering, sort data, pagination and column order and visibility control. * * To create table you must set {@link TableProps.rows} with data, configure columns by {@link TableProps.columns} * and set total rows count by {@link TableProps.totalRows}. * * Also, you should provide {@link TableProps.rowIdProvider} function that should return unique key for given row. * * ## Columns configuration * * To configure columns define list of available columns in {@link TableProps.columns} and define * column render in {@link TableHeader} and {@link TableBody}. * * Pay attention that {@link TableRow} should be memoized for performance issue. * * ```tsx * <Table columns={[Columns.Name]}> * <TableHeader> * <TableHeaderCell column={Columns.Name}>Name</TableHeaderCell> * </TableHeader> * * <TableBody<RowData>>{(row) => <MyTableRowMemo row={row} />}</TableBody> * </Table> * * // Somewhere in different place * function MyTableRow({ row }: { row: RowData }) { * return ( * <TableRow linkTo="dashboard"> * <TableCell column={Columns.Name}>{row.name}</TableCell> * </TableRow> * ); * } * * const MyTableRowMemo = memo(MyTableRow); * ``` * * ## Rows per page * * {@link Table} supports rows per change feature. To enable it you must use {@link TableRowsPerPage} component * in {@link TableFooter}. * * ```tsx * <TableFooter> * <TableRowsPerPage rowsPerPage={rowsPerPage} onRowsPerPageChange={setRowsPerPage} /> * </TableFooter> * ``` * * ## Pagination * * {@link Table} supports pagination. To enable it you must use {@link TablePagination} component * in {@link TableFooter}. * * ```tsx * <TableFooter> * <TablePagination * rowsPerPage={rowsPerPage} * currentPage={currentPage} * linkToBuilder={(page) => `/?page=${page}`} * /> * </TableFooter> * ``` * * Pagination should be implemented by some URL search query params for best user experience. * * ```tsx * const { search } = useLocation(); * const currentPage = Number(new URLSearchParams(search).get('page') || '0'); * ``` * * ## Column sort * * {@link Table} supports column sort by {@link TableProps.sort} and {@link TableProps.onSortChanged} * {@link Table} props and {@link TableHeaderCellProps.sortable} {@link TableHeaderCell} props. * * Set current sort in {@link TableProps.sort} and define header that should be sortable by * {@link TableHeaderCellProps.sortable}. * * ```tsx * <Table * sort={currentSort} * onSortChanged={handleSortChanged} * > * <TableHeader> * <TableHeaderCell column={Columns.Name} sortable>Name</TableHeaderCell> * </TableHeader> * </Table> * ``` * * ## Row actions * * {@link Table} supports row actions that will be shown on each row at rightTo enable it you must use * {@link TableActionsCell} component in {@link TableRow}. * * ```tsx * <TableRow> * <TableActionsCell> * <TableAction icon={IconGlyph.Edit} onClick={editClickHandler}>Edit</TableAction> * <TableAction icon={IconGlyph.Delete} onClick={deleteClickHandler}>Delete</TableAction> * </TableActionsCell> * </TableRow> * ``` * * ## Rows selection * * Fot select some rows in {@link Table} provide {@link TableProps.selection} property with selection mode * and {@link TableSelection.selectedIds} or {@link TableSelection.unselectedIds} row IDs. * And provide {@link TableProps.onSelectionChanged} property to process selection change events. * * ```tsx * <Table * selection={currentSelection} * onSelectionChanged={handleSelectionChanged} * > * // ... * </Table> * ``` * * ### Disable selection * * To disable rows selection set `false` to {@link TableProps.rowSelectionEnabled}. * * ```tsx * <Table rowSelectionEnabled={false}> * // ... * </Table> * ``` * * ## Interaction * * If you need to open some URL or run some code when a row is clicked, you should use * {@link TableRowProps.linkTo} or {@link TableRowProps.onClick} props. * * ```tsx * <TableRow linkTo="some_url"> * // ... * </TableRow> * ``` * * ## States * * {@link Table} provide some special states. * * ### Empty state * * If there are no rows to display, you can set specific content that should be displayed by * {@link TableNoRowsBody} component. * * ```tsx * <Table> * <TableNoRowsBody> * <EmptyState> * <EmptyStateHeader>There are no items</EmptyStateHeader> * <EmptyStateBody>Click "Add item" button to add one</EmptyStateBody> * <EmptyStateButton>Add item</EmptyStateButton> * </EmptyState> * </TableNoRowsBody> * </Table> * ``` * * ### Loading state * * You can pass {@link TableProps.loading} props to indicate that table is in loading. * * If table has no data and state is loading then preload indicator will be shown. * * ```tsx * <Table loading> * // ... * </Table> * ``` * * ## Complex example * * ```tsx * interface RowData { * id: string; * name: string; * phone: string; * } * * enum Columns { * Name, * Phone * } * * function Users() { * const rows: RowData[] = [ * // Some data * ]; * const totalRows = 1000; * const [ rowsPerPage, setRowsPerPage ] = useState(25); * const rowIdProvider = useCallback((row: RowData) => row.id, []); * * const { search } = useLocation(); * const currentPage = Number(new URLSearchParams(search).get('page') || '0'); * * return ( * <Table * columns={[Columns.Name, Columns.Phone]} * rows={rows} * rowIdProvider={rowIdProvider} * totalRows={totalRows} * > * <TableCaption> * <TableCaptionTitle>Table title</TableCaptionTitle> * <TableCaptionSummary>Table sub title</TableCaptionSummary> * </TableCaption> * * <TableHeader> * <TableHeaderCell column={Columns.Name} sortable> * Name * </TableHeaderCell> * <TableHeaderCell column={Columns.Phone}> * Phone * </TableHeaderCell> * </TableHeader> * * <TableBody<RowData>>{(row) => <MyTableRowMemo row={row} />}</TableBody> * * <TableNoRowsBody> * <EmptyState> * <EmptyStateHeader>There are no items</EmptyStateHeader> * <EmptyStateBody>Click "Add item" button to add one</EmptyStateBody> * <EmptyStateButton>Add item</EmptyStateButton> * </EmptyState> * </TableNoRowsBody> * * <TableNoColumnsBody> * <EmptyState> * <EmptyStateHeader>All table columns are hidden</EmptyStateHeader> * <EmptyStateBody>Click the "Adjust columns" button to choose columns to show</EmptyStateBody> * </EmptyState> * </TableNoColumnsBody> * * <TableFooter> * <TableRowsPerPage rowsPerPage={rowsPerPage} onRowsPerPageChange={setRowsPerPage} /> * <TablePagination * rowsPerPage={rowsPerPage} * currentPage={currentPage} * linkToBuilder={(page) => `/?page=${page}`} * /> * </TableFooter> * </Table> * ); * } * * function MyTableRow({ row }: { row: RowData }) { * const editClickHandler = useCallback(() => {}, []); * const deleteClickHandler = useCallback(() => {}, []); * * return ( * <TableRow> * <TableCell column={Columns.Name}>{row.name}</TableCell> * <TableCell column={Columns.Phone}>{row.phone}</TableCell> * <TableActionsCell> * <TableAction icon={IconGlyph.Edit} onClick={editClickHandler}>Edit</TableAction> * <TableAction icon={IconGlyph.Delete} onClick={deleteClickHandler}>Delete</TableAction> * </TableActionsCell> * </TableRow> * ); * } * * const MyTableRowMemo = memo(MyTableRow); * ``` */ export declare function Table<C extends string, D extends object>(props: TableProps<C, D>): JSX.Element;