diff --git a/docs/api.md b/docs/api.md index 4087440..44ee2fc 100644 --- a/docs/api.md +++ b/docs/api.md @@ -465,13 +465,6 @@ The following options are supported via the main options object passed to `useTa - An object of columnID's and their corresponding filter values. This information is stored in state since the table is allowed to manipulate the filter through user interaction. - `initialState.filters` - Identical to the `state.filters` option above -- `defaultFilter: String | Function` - - If a **function** is passed, it must be **memoized** - - Defaults to `text` - - The function (or resolved function from the string) will be used as the default/fallback filter method for every column that has filtering enabled. - - If a `string` is passed, the function with that name located on the `filterTypes` option object will be used. - - If a `function` is passed, it will be used. - - For more information on filter types, see Filtering - `manualFilters: Bool` - Enables filter detection functionality, but does not automatically perform row filtering. - Turn this on if you wish to implement your own row filter outside of the table (eg. server-side or manual row grouping/nesting) diff --git a/index.d.ts b/index.d.ts index afe2a52..9071664 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,281 +1,630 @@ -declare module 'react-table' { - import { ReactNode, useState } from 'react' +// TypeScript Version: 3.5 - type StringKey = Extract - type IdType = StringKey | string +import { ReactNode, ComponentType, MouseEvent } from 'react' - type SortingRule = { - id: IdType - desc: boolean - } +/** + * The empty definitions of below provides a base definition for the parts used by useTable, that can then be extended in the users code. + * + * @example + * export interface TableOptions + * extends + * UseExpandedOptions, + * UseFiltersOptions {} + */ +export interface TableOptions extends UseTableOptions {} - export type SortingRules = SortingRule[] +export interface TableInstance + extends Omit, 'columns' | 'state'>, + UseTableInstanceProps {} - export type SortByFn = (a: any, b: any, desc: boolean) => 0 | 1 | -1 +export interface TableState< + D extends object = {} +> {} /* tslint:disable-line no-empty-interface */ // eslint-disable-line @typescript-eslint/no-empty-interface - export type Filters = Record, string> +export interface Hooks extends UseTableHooks {} - export interface Cell extends TableInstance { - cell: { value: any } - column: Column - row: Row - render: (type: 'Cell' | 'Aggregated', userProps?: any) => any - isGrouped?: boolean - isAggregated?: boolean - isRepeatedValue?: boolean - getCellProps: () => any - } +export interface Cell extends UseTableCellProps {} - export interface Row { - index: number - cells: Cell[] - getRowProps: (userProps?: any) => any - original: D - path: any[] - values: any[] - depth: number - } +export interface Column + extends UseTableColumnOptions {} - export interface UseExpandedRow { - subRows?: D[] - groupByID?: string | number - toggleExpanded?: () => any - isExpanded?: boolean - isAggregated?: boolean - } +export interface ColumnInstance + extends Omit, 'id'>, + UseTableColumnProps {} - export type AccessorFn = ( - originalRow: D, - index: number, - sub: { - subRows: [D] - depth: number - data: [D] - } - ) => unknown +export interface HeaderGroup + extends ColumnInstance, + UseTableHeaderGroupProps {} - export interface HeaderColumn { - /** - * This string/function is used to build the data model for your column. - */ - accessor: IdType | AccessorFn - Header?: ReactNode | ((props: TableInstance) => ReactNode) - Filter?: ReactNode | ((props: TableInstance) => ReactNode) - Cell?: ReactNode | ((cell: Cell) => ReactNode) - /** - * This is the unique ID for the column. It is used by reference in things like sorting, grouping, filtering etc. - */ - id?: IdType - minWidth?: string | number - maxWidth?: string | number - width?: string | number - disableSorting?: boolean - canSortBy?: boolean - sortByFn?: SortByFn - defaultSortDesc?: boolean - isAggregated?: any - } +export interface Row extends UseTableRowProps {} - export interface Column extends HeaderColumn { - show?: boolean | ((instance: TableInstance) => boolean) - columns?: Column[] - } +/* #region useTable */ +export function useTable( + options: TableOptions, + ...plugins: PluginHook[] +): TableInstance - export type Page = Row[] +/** + * NOTE: To use custom options, use "Interface Merging" to add the custom options + */ +export type UseTableOptions = { + columns: Column[] + data: D[] +} & Partial<{ + initialState: Partial> + state: Partial> + reducer: ( + oldState: TableState, + newState: TableState, + type: string + ) => TableState + defaultColumn: Partial> + initialRowStateKey: IdType + getSubRows: (row: Row, relativeIndex: number) => Row[] + getRowID: (row: Row, relativeIndex: number) => string + debug: boolean +}> - export interface EnhancedColumn - extends Omit, 'columns'>, - TableInstance { - id: IdType - column: Column - render: (type: 'Header' | 'Filter', userProps?: any) => any - getHeaderProps: (userProps?: any) => any - getSortByToggleProps: (userProps?: any) => any - isSorted: boolean - isSortedDesc: boolean - sortedIndex: number - isVisible: boolean - canSort?: boolean - } +export interface UseTableHooks { + columnsBeforeHeaderGroups: (( + flatColumns: Column[], + instance: TableInstance + ) => Column[])[] + columnsBeforeHeaderGroupsDeps: (( + deps: any[], + instance: TableInstance + ) => any[])[] + useMain: ((instance: TableInstance) => TableInstance)[] + useRows: ((rows: Row[], instance: TableInstance) => Row[])[] + prepareRow: ((row: Row, instance: TableInstance) => Row)[] - export interface HeaderGroup { - headers: EnhancedColumn[] - getHeaderGroupProps: (userProps?: any) => any - } - - export interface Hooks { - columnsBeforeHeaderGroups: any[] - columnsBeforeHeaderGroupsDeps: any[] - useMain: any[] - useColumns: any[] - useHeaders: any[] - useHeaderGroups: any[] - useRows: any[] - prepareRow: any[] - getTableProps: any[] - getRowProps: any[] - getHeaderGroupProps: any[] - getHeaderProps: any[] - getCellProps: any[] - } - - export interface RowsProps { - subRowsKey: string - } - - export interface FiltersProps { - filterFn: () => void - manualFilters: boolean - disableFilters: boolean - setFilter: () => any - setAllFilters: () => any - } - - export interface UsePaginationState { - pageIndex: number - pageSize: number - pageCount: number - rowCount: number - } - - export interface UsePaginationValues { - page: Page - pageIndex: number // yes, this is on instance and state - pageSize: number // yes, this is on instance and state - canPreviousPage: boolean - canNextPage: boolean - nextPage: () => any - previousPage: () => any - setPageSize: (size: number) => any - pageOptions: any[] - manualPagination: boolean - paginateExpandedRows: boolean - disablePageResetOnDataChange: boolean - pageCount: number - gotoPage: (page: number) => any - } - - export interface UseFiltersState { - filters?: Filters - } - - export interface UseFiltersValues { - setFilter: (columnID: keyof D, value: string) => void - setAllFilters: (values: Filters) => void - disableFilters: boolean - } - - export interface UseGroupByValues { - groupByFn: any - manualGroupBy: boolean - disableGrouping: boolean - aggregations: any - } - - export interface UseGroupByState { - groupBy: string[] - isAggregated?: boolean - } - - export interface UseExpandedValues { - toggleExpanded?: () => any - } - - export interface UseSortbyOptions { - sortByFn?: SortByFn - manualSorting?: boolean - disableSorting?: boolean - defaultSortDesc?: boolean - disableMultiSort?: boolean - } - - export interface UseSortbyState { - sortBy?: SortingRules - } - - export interface TableInstance extends TableOptions { - hooks: Hooks - rows: Row[] - columns: EnhancedColumn[] - headerGroups: HeaderGroup[] - headers: HeaderGroup[] - getTableProps: (userProps?: any) => any - getRowProps: (userProps?: any) => any - prepareRow: (row: Row) => any - state: TableState - setState: SetState - } - - export interface TableOptions { - data: D[] - columns: HeaderColumn[] - debug?: boolean - loading: boolean - defaultColumn?: Partial> - initialState?: Partial> - state?: Partial> - reducer?: ( - oldState: TableState, - newState: TableState, - type: string - ) => any - } - - // The empty definition of TableState is not an error. It provides a definition - // for the state, that can then be extended in the users code. - // - // e.g. - // - // export interface TableState - // extends UsePaginationState, - // UseGroupByState, - // UseSortbyState, - // UseFiltersState {} - - // eslint-disable-next-line @typescript-eslint/no-empty-interface - export interface TableState {} - - export type SetState = ( - updater: (old: TableState) => TableState, - actions: any - ) => void - - export function useTable( - props: TableOptions, - ...plugins: any[] - ): TableInstance - - export function useFilters( - props: TableOptions - ): TableOptions & { - rows: Row[] - } - - export function useSortBy( - props: TableOptions - ): TableOptions & { - rows: Row[] - } - - export function useGroupBy( - props: TableOptions - ): TableOptions & { rows: Row[] } - - export function usePagination( - props: TableOptions - ): UsePaginationValues - - export function useExpanded( - props: TableOptions - ): TableOptions & { - toggleExpandedByPath: () => any - expandedDepth: [] - rows: Row[] - } - - export const actions: Record - - export function addActions(...actions: string[]): void - - export const defaultState: Record + // Prop Hooks + getTableProps: ((instance: TableInstance) => object)[] + getTableBodyProps: ((instance: TableInstance) => object)[] + getRowProps: ((row: Row, instance: TableInstance) => object)[] + getHeaderGroupProps: (( + headerGroup: HeaderGroup, + instance: TableInstance + ) => object)[] + getHeaderProps: ((column: Column, instance: TableInstance) => object)[] + getCellProps: ((cell: Cell, instance: TableInstance) => object)[] } + +export interface UseTableColumnOptions + extends Accessor, + Partial<{ + columns: Column[] + show: boolean | ((instance: TableInstance) => boolean) + Header: Renderer> + Cell: Renderer> + width?: number + minWidth?: number + maxWidth?: number + }> {} + +export interface UseTableInstanceProps { + columns: ColumnInstance[] + flatColumns: ColumnInstance[] + headerGroups: HeaderGroup[] + headers: ColumnInstance[] + flatHeaders: ColumnInstance[] + rows: Row[] + getTableProps: (props?: object) => object + getTableBodyProps: (props?: object) => object + prepareRow: (row: Row) => void + rowPaths: string[] + flatRows: Row[] + state: TableState + setState: SetState + totalColumnsWidth: number +} + +export interface UseTableHeaderGroupProps { + headers: ColumnInstance[] + getHeaderGroupProps: (props?: object) => object + totalHeaderCount: number +} + +export interface UseTableColumnProps { + id: IdType + isVisible: boolean + render: (type: 'Header' | string, props?: object) => ReactNode + getHeaderProps: (props?: object) => object + parent: ColumnInstance + depth: number + index: number +} + +export interface UseTableRowProps { + cells: Cell[] + values: Record, CellValue> + getRowProps: (props?: object) => object + index: number + original: D + path: IdType[] + subRows: Row[] +} + +export interface UseTableCellProps { + column: ColumnInstance + row: Row + value: CellValue + getCellProps: (props?: object) => object + render: (type: 'Cell' | string, userProps?: object) => ReactNode +} + +export type HeaderProps = TableInstance & { + column: ColumnInstance +} & Record +export type CellProps = TableInstance & { + column: ColumnInstance + row: Row + cell: Cell +} & Record + +// NOTE: At least one of (id | accessor | Header as string) required +export interface Accessor { + accessor?: + | IdType + | (( + originalRow: D, + index: number, + sub: { + subRows: D[] + depth: number + data: D[] + } + ) => CellValue) + id?: IdType +} +/* #endregion */ + +// Plugins + +/* #region useColumnOrder */ +export function useColumnOrder(hooks: Hooks): void +export namespace useColumnOrder { + const pluginName = 'useColumnOrder' +} + +export interface UseColumnOrderState { + columnOrder: IdType[] +} + +export interface UseColumnOrderInstanceProps { + setColumnOrder: (updater: (columnOrder: IdType[]) => IdType[]) => void +} +/* #endregion */ + +/* #region useExpanded */ +export function useExpanded(hooks: Hooks): void +export namespace useExpanded { + const pluginName = 'useExpanded' +} + +export type UseExpandedOptions = Partial<{ + getSubRows: (row: Row, relativeIndex: number) => Row[] + manualExpandedKey: IdType + paginateExpandedRows: boolean +}> + +export interface UseExpandedHooks { + getExpandedToggleProps: (( + row: Row, + instance: TableInstance + ) => object)[] +} + +export interface UseExpandedState { + expanded: IdType[] +} + +export interface UseExpandedInstanceProps { + rows: Row[] + toggleExpandedByPath: (path: IdType[], isExpanded: boolean) => void + expandedDepth: number +} + +export interface UseExpandedRowProps { + isExpanded: boolean + canExpand: boolean + subRows: Row[] + toggleExpanded: (isExpanded?: boolean) => void + getExpandedToggleProps: (props?: object) => object +} +/* #endregion */ + +/* #region useFilters */ +export function useFilters(hooks: Hooks): void +export namespace useFilters { + const pluginName = 'useFilters' +} + +export type UseFiltersOptions = Partial<{ + manualFilters: boolean + disableFilters: boolean + filterTypes: Filters +}> + +export interface UseFiltersState { + filters: Filters +} + +export type UseFiltersColumnOptions = Partial<{ + disableFilters: boolean + Filter: Renderer> + filter: FilterType | DefaultFilterTypes | keyof Filters +}> + +export interface UseFiltersInstanceProps { + rows: Row[] + preFilteredRows: Row[] + setFilter: ( + columnId: IdType, + updater: ((filterValue: FilterValue) => FilterValue) | FilterValue + ) => void + setAllFilters: ( + updater: Filters | ((filters: Filters) => Filters) + ) => void +} + +export interface UseFiltersColumnProps { + canFilter: boolean + setFilter: ( + updater: ((filterValue: FilterValue) => FilterValue) | FilterValue + ) => void + filterValue: FilterValue + preFilteredRows: Row[] + filteredRows: Row[] +} + +export type FilterProps = HeaderProps +export type FilterValue = any +export type Filters = Record, FilterValue> + +export type DefaultFilterTypes = + | 'text' + | 'exactText' + | 'exactTextCase' + | 'includes' + | 'includesAll' + | 'exact' + | 'equals' + | 'between' + +export interface FilterType { + ( + rows: Row[], + columnId: IdType, + filterValue: FilterValue, + column: ColumnInstance + ): Row[] + autoRemove?: (filterValue: FilterValue) => boolean +} +/* #endregion */ + +/* #region useGroupBy */ +export function useGroupBy(hooks: Hooks): void +export namespace useGroupBy { + const pluginName = 'useGroupBy' +} + +export type UseGroupByOptions = Partial<{ + manualGroupBy: boolean + disableGrouping: boolean + aggregations: Record> + groupByFn: (rows: Row[], columnId: IdType) => Record> +}> + +export interface UseGroupByHooks { + getGroupByToggleProps: (( + header: HeaderGroup, + instance: TableInstance + ) => object)[] +} + +export interface UseGroupByState { + groupBy: IdType[] +} + +export type UseGroupByColumnOptions = Partial<{ + aggregate: Aggregator | Aggregator[] + Aggregated: Renderer> + disableGrouping: boolean + groupByBoundary: boolean +}> + +export interface UseGroupByInstanceProps { + rows: Row[] + preGroupedRows: Row[] + toggleGroupBy: (columnId: IdType, toggle: boolean) => void +} + +export interface UseGroupByColumnProps { + canGroupBy: boolean + isGrouped: boolean + groupedIndex: number + toggleGroupBy: () => void +} + +export interface UseGroupByHeaderProps { + getGroupByToggleProps: (props?: object) => object +} + +export interface UseGroupByRowProps { + isAggregated: boolean + groupByID: IdType + groupByVal: string + values: Record, AggregatedValue> + subRows: Row[] + depth: number + path: IdType[] + index: number +} + +export interface UseGroupByCellProps { + isGrouped: boolean + isRepeatedValue: boolean + isAggregated: boolean +} + +export type DefaultAggregators = + | 'sum' + | 'average' + | 'median' + | 'uniqueCount' + | 'count' + +export type AggregatorFn = ( + columnValues: CellValue[], + rows: Row[] +) => AggregatedValue +export type Aggregator = + | AggregatorFn + | DefaultAggregators + | string +export type AggregatedValue = any +/* #endregion */ + +/* #region usePagination */ +export function usePagination(hooks: Hooks): void +export namespace usePagination { + const pluginName = 'usePagination' +} + +export type UsePaginationOptions = Partial<{ + pageCount: number + manualPagination: boolean + disablePageResetOnDataChange: boolean + paginateExpandedRows: boolean +}> + +export interface UsePaginationState { + pageSize: number + pageIndex: number +} + +export interface UsePaginationInstanceProps { + page: Row[] + pageCount: number + pageOptions: number[] + canPreviousPage: boolean + canNextPage: boolean + gotoPage: (updater: ((pageIndex: number) => number) | number) => void + previousPage: () => void + nextPage: () => void + setPageSize: (pageSize: number) => void + pageIndex: number + pageSize: number +} +/* #endregion */ + +/* #region useRowSelect */ +export function useRowSelect(hooks: Hooks): void +export namespace useRowSelect { + const pluginName = 'useRowSelect' +} + +export type UseRowSelectOptions = Partial<{ + manualRowSelectedKey: IdType +}> + +export interface UseRowSelectHooks { + getToggleRowSelectedProps: (( + row: Row, + instance: TableInstance + ) => object)[] + getToggleAllRowsSelectedProps: ((instance: TableInstance) => object)[] +} + +export interface UseRowSelectState { + selectedRows: IdType[] +} + +export interface UseRowSelectInstanceProps { + toggleRowSelected: (rowPath: IdType, set?: boolean) => void + toggleRowSelectedAll: (set?: boolean) => void + getToggleAllRowsSelectedProps: (props?: object) => object + isAllRowsSelected: boolean +} + +export interface UseRowSelectRowProps { + isSelected: boolean + toggleRowSelected: (set?: boolean) => void + getToggleRowSelectedProps: (props?: object) => object +} +/* #endregion */ + +/* #region useRowState */ +export function useRowState(hooks: Hooks): void +export namespace useRowState { + const pluginName = 'useRowState' +} + +export type UseRowStateOptions = Partial<{ + initialRowStateAccessor: (row: Row) => UseRowStateLocalState +}> + +export interface UseRowStateState { + rowState: Partial<{ + cellState: UseRowStateLocalState + rowState: UseRowStateLocalState + }> +} + +export interface UseRowStateInstanceProps { + setRowState: (rowPath: string[], updater: UseRowUpdater) => void // Purposely not exposing action + setCellState: ( + rowPath: string[], + columnID: IdType, + updater: UseRowUpdater + ) => void +} + +export interface UseRowStateRowProps { + state: UseRowStateLocalState + setState: (updater: UseRowUpdater) => void +} +export interface UseRowStateCellProps { + state: UseRowStateLocalState + setState: (updater: UseRowUpdater) => void +} + +export type UseRowUpdater = T | ((prev: T) => T) +export type UseRowStateLocalState = Record< + IdType, + T +> +/* #endregion */ + +/* #region useSortBy */ +export function useSortBy(hooks: Hooks): void +export namespace useSortBy { + const pluginName = 'useSortBy' +} + +export type UseSortByOptions = Partial<{ + manualSorting: boolean + disableSorting: boolean + disableMultiSort: boolean + isMultiSortEvent: (e: MouseEvent) => boolean + maxMultiSortColCount: number + disableSortRemove: boolean + disabledMultiRemove: boolean + orderByFn: ( + rows: Row[], + sortFns: SortByFn[], + directions: boolean[] + ) => Row[] // CHECK + sortTypes: Record> +}> + +export interface UseSortByHooks { + getSortByToggleProps: (( + column: Column, + instance: TableInstance + ) => object)[] +} + +export interface UseSortByState { + sortBy: SortingRule[] +} + +export type UseSortByColumnOptions = Partial<{ + disableSorting: boolean + sortDescFirst: boolean + sortInverted: boolean + sortType: SortByFn | DefaultSortTypes | string +}> + +export interface UseSortByInstanceProps { + rows: Row[] + preSortedRows: Row[] + toggleSortBy: ( + columnId: IdType, + descending: boolean, + isMulti: boolean + ) => void +} + +export interface UseSortByColumnProps { + canSort: boolean + toggleSortBy: (descending: boolean, multi: boolean) => void + getSortByToggleProps: (props?: object) => object + clearSorting: () => void + isSorted: boolean + sortedIndex: number + isSortedDesc: boolean | undefined +} + +export type SortByFn = ( + rowA: Row, + rowB: Row, + columnId: IdType +) => 0 | 1 | -1 + +export type DefaultSortTypes = 'alphanumeric' | 'datetime' | 'basic' + +export interface SortingRule { + id: IdType + desc?: boolean +} +/* #endregion */ + +/* #region useAbsoluteLayout */ +export function useAbsoluteLayout(hooks: Hooks): void +export namespace useAbsoluteLayout { + const pluginName = 'useAbsoluteLayout' +} +/* #endregion */ + +/* #region useBlockLayout */ +export function useBlockLayout(hooks: Hooks): void +export namespace useBlockLayout { + const pluginName = 'useBlockLayout' +} +/* #endregion */ + +/* #region useResizeColumns */ +export function useResizeColumns(hooks: Hooks): void +export namespace useResizeColumns { + const pluginName = 'useResizeColumns' +} + +export interface UseResizeColumnsOptions { + disableResizing?: boolean +} + +export interface UseResizeColumnsColumnOptions { + disableResizing?: boolean +} + +export interface UseResizeColumnsHeaderProps { + getResizerProps: (props?: object) => object + canResize: boolean + isResizing: boolean +} +/* #endregion */ + +// Additional API +export const actions: Record +export function addActions(...actions: string[]): void + +export const defaultState: Record + +// Helpers +export type StringKey = Extract +export type IdType = StringKey | string +export type CellValue = any + +export type Renderer = ComponentType | ReactNode + +export interface PluginHook { + (hooks: Hooks): void + pluginName: string +} + +export type SetState = ( + updater: (old: TableState) => TableState, + type: keyof typeof actions +) => void