@tiller-ds/data-display
Version:
Data display module of Tiller Design System
322 lines (321 loc) • 14.1 kB
TypeScript
import * as React from "react";
import { Cell, Row } from "react-table";
import { CardHeaderProps } from "@tiller-ds/core";
import { ComponentTokens, TokenProps } from "@tiller-ds/theme";
declare type DataTableChild<T extends object> = React.ReactElement<DataTableColumnProps<T> | DataTableExpanderProps<T>> | React.ReactElement<DataTableColumnProps<T> | DataTableExpanderProps<T>>[] | boolean | undefined;
export declare type DataTableProps<T extends object> = {
/**
* Aligns the headers of the data table to a specific position.
*/
alignHeader?: "left" | "right" | "center" | "justify";
/**
* Children wrapped in the data table. Most often DataTable.Column, DataTable.Selector,
* DataTable.CardHeader, etc.
*/
children: DataTableChild<T> | DataTableChild<T>[];
/**
* Data array of any type to be shown in the data table.
*/
data: T[];
/**
* Receives an object array of type SortInfo (column, sortDirection) and sorts
* the data table accordingly. Column attribute represents a string which corresponds
* to a certain column name, while sortDirection is either ASCENDING or DESCENDING.
*/
defaultSortBy?: SortInfo[];
/**
* Controls table sorting behavior when clicking a column header by returning to a default sorted state defined by `defaultSortBy` prop when sort resets.
*
* By default, clicking a column header cycles through sorting states, and a sort reset returns the table to an unsorted state.
* Setting this prop to `true` prevents this default behavior.
*
* With this prop enabled, clicking the header of a column defined in `defaultSortBy` will toggle between ascending and descending order **even after a sort reset**.
* This allows you to maintain the initial sort order throughout user interaction.
*
* @defaultValue false
*/
retainDefaultSortBy?: boolean;
/**
* For getting each item's unique identifier on DataTable initialization.
* Ex. (item: Item) => item.id
*/
getItemId?: (item: T, index: number) => string | number;
/**
* Useful for styling each row conditionally. For example, if item's id % 2 === 0
* set the row class name to pink (return pink), otherwise return purple.
*/
getRowClassName?: (values: T, index: number) => string;
/**
* Hook for connecting the data table to a variable which uses the 'useDataTable()' hook.
* The hook manages selection of items in the data table, sorting, etc.
*/
hook?: DataTableHook;
/**
* Makes the rows clickable and executes a custom function when a single click is executed.
* The function takes the entity of a clicked row as a parameter.
*
* @note If a button is placed within a row, ensure to call `e.stopPropagation()` within its
* `onClick` event handler to prevent event bubbling and unintended triggering of the
* row's `onClick` handler. This isolates button actions and prevents conflicts.
*/
onClick?: (rowValue: T) => void;
/**
* Makes the rows double clickable and executes a custom function when a double click is executed.
* The function takes the entity of a clicked row as a parameter.
*
* @note If a button is placed within a row, ensure to call `e.stopPropagation()` within its
* `onDoubleClick` event handler to prevent event bubbling and unintended triggering of the
* row's `onDoubleClick` handler. This isolates button actions and prevents conflicts.
*/
onDoubleClick?: (rowValue: T) => void;
/**
* Identifies the row which can be edited.
*/
rowEditingIndex?: number;
/**
* Determines whether the row can be saved according to its value.
* Useful if, for example, a validation fails, and you want to disable the save button accordingly.
*/
saveEnabled?: boolean;
/**
* Enables the display of a footer below the data table.
*/
showFooter?: boolean;
/**
* Enables the display of a header above the data table.
*/
showHeader?: boolean;
/**
* Enables fixed first column in horizontal scroll data table.
*/
firstColumnFixed?: boolean;
/**
* Enables fixed last column in horizontal scroll data table.
*/
lastColumnFixed?: boolean;
/**
* Custom classes for the container.
* Overrides conflicting default styles, if any.
*
* The provided `className` is processed using `tailwind-merge` to eliminate redundant or conflicting Tailwind classes.
*/
className?: string;
/**
* Content to be displayed when the dataset is empty.
*/
emptyState?: React.ReactNode;
/**
* Enable or disable multi-column sorting.
* When set to true, users can sort by multiple columns simultaneously.
*/
multiSort?: boolean;
/**
* A unique identifier for testing purposes.
* This identifier can be used in testing frameworks like Jest or Cypress to locate specific elements for testing.
* It helps ensure that UI components are behaving as expected across different scenarios.
* @type {string}
* @example
* // Usage:
* <MyComponent data-testid="my-component" />
* // In tests:
* getByTestId('my-component');
*/
"data-testid"?: string;
} & DataTableTokensProps;
declare type DataTableTokensProps = {
tokens?: ComponentTokens<"DataTable">;
};
declare type Meta = {
isEditMode: boolean;
};
declare type DataTableColumnProps<T extends object> = {
/**
* Represents the column label in the header (not exclusively text).
*/
header?: React.ReactNode;
/**
* Represents the column label in the footer (not exclusively text).
* Note that the default value of the showFooter DataTable prop is false, so it needs to be set to true.
*/
footer?: React.ReactNode;
/**
* The title prop adds a tooltip with title text to the table header/footer cell.
* Hovering the mouse over the header/footer cell will display the tooltip.
*/
title?: string;
/**
* Custom classes for the container.
* Overrides conflicting default styles, if any.
*
* The provided `className` is processed using `tailwind-merge` to eliminate redundant or conflicting Tailwind classes.
*/
className?: string;
/**
* Determines whether this column is sortable when clicking on its header.
*/
canSort?: boolean;
/**
* Defines the number of columns a cell should span.
*/
colSpan?: number;
/**
* Aligns the column data to a specific position.
*/
align?: "left" | "right" | "center" | "justify";
} & ({
/**
* Accessor is the key in the data (used for mapping column to the matching data).
* (check here for details: https://react-table-v7.tanstack.com/docs/api/useTable#column-options).
*/
accessor: string;
} | {
/**
* Additional options to pass onto as children of the column.
* item: describes current item shown in the cell.
* index: represents the index of the item (starting at 0).
* row: check https://react-table-v7.tanstack.com/docs/api/useTable#row-properties.
* isEditMode: returns true if the column is currently in edit mode.
* saveEnabled: returns false if there is no value present in the selected column (useful for disabling save buttons when editing).
*/
children: (item: T, index: number, row: Row<T>, isEditMode: Meta, saveEnabled: boolean) => React.ReactNode;
/**
* Unique ID for the column. It is used by reference in things like sorting, grouping, filtering etc.
* If a string accessor is used, it defaults as the column ID, but can be overridden if necessary.
*/
id: string;
}) & TokenProps<"DataTable">;
declare type DataTableExpanderProps<T extends object> = {
/**
* Defines whether a given row should be expandable.
*
* @param {T} item - The data item for the row.
* @param {number} index - The index of the row.
* @returns {boolean} - Returns true if the row is expandable, otherwise false.
*/
predicate?: (item: T, index: number) => boolean;
/**
* The component rendered when the predicate prop is not satisfied.
*
* @param {T} item - The data item for the row.
* @param {number} index - The index of the row.
* @returns {React.ReactNode} - The custom component to render.
*/
predicateFallback?: (item: T, index: number) => React.ReactNode;
/**
* Expander content displayed when the expander is clicked.
*
* @param {T} item - The data item for the row.
* @param {number} index - The index of the row.
* @returns {React.ReactNode} - The content to display in the expanded row.
*/
children: (item: T, index: number) => React.ReactNode;
/**
* Custom classes for the container.
* Overrides conflicting default styles, if any.
*
* The provided `className` is processed using `tailwind-merge` to eliminate redundant or conflicting Tailwind classes.
*/
className?: string;
};
declare type DataTableSelectorProps<T extends object> = {
/**
* Defines whether a given row should be selectable.
*/
predicate?: (item: T, index: number) => boolean;
children?: (item: T, index: number, row: Row<T>, predicate: boolean) => React.ReactNode;
};
declare type DataTableCardHeaderProps = {
/**
* Content wrapped in the data table card header. Most often DataTable.CardHeader.Title and DataTable.CardHeader.Actions.
*/
children?: React.ReactNode;
/**
* Selects the desired number of rows and shows message in header that this number of rows are selected.
*/
selectedCount: number;
/**
* Selects all rows in DataTable and shows message in header that all rows are selected.
*/
isAllRowsSelected: boolean;
/**
* Changes the number of total elements in the message when selecting rows (e.g. 5 selected out of {totalElements} items).
*/
totalElements: number;
} & CardHeaderProps & TokenProps<"DataTable">;
declare type DataTableHook = {
setSelected: (selection: Record<string, boolean>, isAllRowsSelected: boolean) => void;
setSortBy: (sort: SortInfo[]) => void;
selected: Record<string, boolean>;
isAllRowsSelected: boolean;
toggleSelectAll: () => void;
};
export declare type SortInfo = {
column: string;
sortDirection: "ASCENDING" | "DESCENDING";
};
declare type DataTablePrimaryRowProps = {
children: React.ReactNode;
};
declare type DataTableSecondaryRowProps = {
children: React.ReactNode;
};
declare type UseDataTable = [{
selected: Record<string, boolean>;
selectedCount: number;
isAllRowsSelected: boolean;
sortBy: SortInfo[];
defaultSortBy: SortInfo[];
}, DataTableHook];
declare type DataTableCardHeaderSelectorProps = {
children?: (selectorInfo: SelectorInfo) => React.ReactNode;
};
declare type SelectorInfo = {
selectedCount: React.ReactNode;
totalElements: React.ReactNode;
};
declare type DataTableContext<T> = {
data: T[];
totalNumberOfElements: number;
hook?: DataTableHook;
getItemId: (item: T, index: number) => string | number;
predicate: (item: T, index: number) => boolean;
};
declare const DataTableContext: React.Context<DataTableContext<any> | undefined>;
export declare function useDataTableContext<T = unknown>(): DataTableContext<T>;
declare type UseDataTableProps = {
defaultSortBy?: SortInfo[];
};
export declare function useDataTable({ defaultSortBy }?: UseDataTableProps): UseDataTable;
declare type Operation = "sum" | "average";
declare type DataTableSummary<T> = {
key: keyof T;
operation: Operation;
};
export declare function useLocalSummary<T>(data: T[], summaryList: DataTableSummary<T>[]): Record<keyof T, Record<Operation, number>>;
declare function DataTable<T extends object>({ data, hook, showHeader, alignHeader, showFooter, children, defaultSortBy, getItemId, onClick, onDoubleClick, getRowClassName, rowEditingIndex, saveEnabled, firstColumnFixed, lastColumnFixed, className, multiSort, retainDefaultSortBy, ...props }: DataTableProps<T>): JSX.Element;
declare function DataTablePrimaryRow({ children }: DataTablePrimaryRowProps): JSX.Element;
declare function DataTableSecondaryRow({ children }: DataTableSecondaryRowProps): JSX.Element;
declare function DataTableCardHeader({ totalElements, selectedCount, isAllRowsSelected, children, ...props }: DataTableCardHeaderProps): JSX.Element;
declare namespace DataTableCardHeader {
var Title: typeof import("../../../dist/libs/core/Card").CardHeaderTitle;
var Actions: typeof import("../../../dist/libs/core/Card").CardHeaderActions;
var Selector: typeof DataTableCardHeaderSelector;
}
declare function DataTableCardHeaderSelector({ children }: DataTableCardHeaderSelectorProps): JSX.Element | null;
declare function SelectorCell<T extends object>({ row, ...props }: Pick<Cell<T>, "row"> & {
"data-testid"?: string;
}): JSX.Element;
declare function DataTableColumn<T extends object>(_: DataTableColumnProps<T>): JSX.Element;
declare function DataTableExpander<T extends object>(_: DataTableExpanderProps<T>): JSX.Element;
declare function DataTableSelector<T extends object>(_: DataTableSelectorProps<T>): JSX.Element;
declare type DataTable = typeof DataTable & {
Column: typeof DataTableColumn;
Expander: typeof DataTableExpander;
Selector: typeof DataTableSelector;
SelectorCell: typeof SelectorCell;
CardHeader: typeof DataTableCardHeader;
PrimaryRow: typeof DataTablePrimaryRow;
SecondaryRow: typeof DataTableSecondaryRow;
};
declare const MemoDataTable: DataTable;
export default MemoDataTable;