[react-bootstrap-table-next] Add typing for react-bootstrap-table-next (#43155)

* react-bootstrap-table-next: add initial typings

* [name react-bootstrap-table2] add modules

* [react-bootstrap-table-next] add filter example

* [react-bootstrap-table2-filter] add filter example

* [react-bootstrap-table-next] update types

- loosen table typing after testing with real life projects
- remove enums in favour of constant declarations and aggregation types

* [react-bootstrap-table-next] fix cell align type

* [react-bootstrap-table-next] update tests

* [react-bootstrap-table2-toolkit] narrow types

* [react-bootstrap-table-next] fix test column

* [react-bootstrap-table2-filter] update comments

* [react-bootstrap-table-next] fix documentation

* [react-bootstrap-table2-filter] fix typo in header

* [react-bootstrap-table-next] fix issues

* [react-bootstrap-table-next] add definitions

- expand toolkit definitions
- add standalone pagination component types

* [react-bootstrap-table-next] loosen column type

* update typescript version

* fix: typescript version mixup

* fix: remove optional chaining, change TS version
This commit is contained in:
Wlad Meixner
2020-04-06 18:42:41 +02:00
committed by GitHub
parent da93d7b130
commit dec598b7cf
16 changed files with 1521 additions and 0 deletions

View File

@@ -0,0 +1,456 @@
// Type definitions for react-bootstrap-table-next 4.0
// Project: https://github.com/react-bootstrap-table/react-bootstrap-table2#readme
// Definitions by: Wlad Meixner <https://github.com/gosticks>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 3.0
// documentation taken from https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/table-props.html
import { CSSProperties, ReactElement, SyntheticEvent, Component } from 'react';
export const ROW_SELECT_SINGLE = 'radio';
export const ROW_SELECT_MULTIPLE = 'checkbox';
export const ROW_SELECT_DISABLED = 'ROW_SELECT_DISABLED';
export const CHECKBOX_STATUS_INDETERMINATE = 'indeterminate';
export const CHECKBOX_STATUS_CHECKED = 'checked';
export const CHECKBOX_STATUS_UNCHECKED = 'unchecked';
export const FILTERS_POSITION_INLINE = 'inline';
export const FILTERS_POSITION_TOP = 'top';
export const FILTERS_POSITION_BOTTOM = 'bottom';
export type RowSelectionType = typeof ROW_SELECT_SINGLE | typeof ROW_SELECT_MULTIPLE | typeof ROW_SELECT_DISABLED;
export type TableCheckboxStatus =
| typeof CHECKBOX_STATUS_INDETERMINATE
| typeof CHECKBOX_STATUS_CHECKED
| typeof CHECKBOX_STATUS_UNCHECKED;
export type FilterPosition =
| typeof FILTERS_POSITION_INLINE
| typeof FILTERS_POSITION_TOP
| typeof FILTERS_POSITION_BOTTOM;
/**
* Table change event types
*/
export type TableChangeType = 'filter' | 'pagination' | 'sort' | 'cellEdit';
/**
* Used to specify the text alignment for a column.
*/
export type CellAlignment = ('left' | 'center' | 'right' | 'start' | 'end') | string;
/**
* Filter comparators used for table filters
*/
declare enum FilterComparator {
LIKE = 'LIKE',
EQ = '=',
NE = '!=',
GT = '>',
GE = '>=',
LT = '<',
LE = '<=',
}
/**
* Sort Order values. 'asc' = ascending, 'desc' = descending.
*/
export type SortOrder = 'asc' | 'desc';
export type ColumnSortFunc<T, E extends keyof T = any> = (
a: T[E],
b: T[E],
order: 'asc' | 'desc',
dataField: any,
rowA: T,
rowB: T,
) => number;
export interface TableChangeState<T> {
page: number;
sizePerPage: number;
sortField: string;
sortOrder: 'asc' | 'desc';
filters: { [key: string]: { filterVal: any; filterType: 'TEXT'; comparator: any } };
data: T[];
cellEdit: {
rowId: string;
dataField: any;
newValue: any;
};
}
export type HeaderFormatter<T extends object = any> = (
column: ColumnDescription<T>,
colIndex: number,
components: {
sortElement: JSX.Element;
filterElement: JSX.Element;
},
) => JSX.Element | string | number | React.ReactText;
export type ColumnFormatter<R, E = any, C = any> = (
cell: C,
row: R,
rowIndex: number,
formatExtraData: E,
) => JSX.Element | string | boolean | React.ReactText;
export interface ColumnDescription<T extends object = any, E = any> {
/**
* If set the column will not use cell values
*/
isDummyField?: boolean;
dataField: any;
formatter?: ColumnFormatter<T, E>;
hidden?: boolean;
/**
* Column header field
*/
text: string;
sort?: boolean;
sortFunc?: ColumnSortFunc<T>;
searchable?: boolean;
align?: CellAlignment;
headerStyle?: React.CSSProperties | (() => React.CSSProperties);
tooltipDataField?: string;
editable?: boolean | ((cell: any, row: T, rowIndex: number, colIndex: number) => boolean);
editor?: { type: string; options?: [{ value: string; label: string }] };
filter?: boolean | TableColumnFilterProps;
filterValue?: (cell: T[keyof T], row: T) => string;
headerAlign?: CellAlignment;
headerFormatter?: HeaderFormatter<T>;
formatExtraData?: {
tooltipFormatter?: (row: T) => JSX.Element;
} & E;
width?: number;
footer?:
| boolean
| number
| string
| ((columnData: any, column: ColumnDescription<T, E>, columnIndex: number) => string);
footerFormatter?: (column: ColumnDescription<T, E>, columnIndex: number) => void;
footerClasses?: string | ((column: ColumnDescription<T, E>, columnIndex: number) => string);
footerStyle?: React.CSSProperties;
footerTitle?: boolean;
footerEvents?: { onClick: (e: any, column: ColumnDescription<T, E>, columnIndex: number) => void };
footerAlign?: CellAlignment | ((column: ColumnDescription<T, E>, colIndex: number) => CellAlignment);
}
/**
* Generic row event handler
*/
export type RowEventHandler<T> = (e: SyntheticEvent, row: T, rowIndex: number) => void;
/**
* Row level event handlers
*/
export type RowEventHandlerProps<T = any> = Partial<{
onClick: RowEventHandler<T>;
onDoubleClick: RowEventHandler<T>;
onMouseEnter: RowEventHandler<T>;
onMouseLeave: RowEventHandler<T>;
onContextMenu: RowEventHandler<T>;
}>;
/**
* Table change callback method
*/
export type TableChangeHandler<T> = (type: TableChangeType, newState: TableChangeState<T>) => void;
/**
* All possible pagination options handled by the pagination plugin
*
* Consult [documentation](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/pagination-props.html)
*/
export type PaginationOptions = Partial<{
custom: boolean;
/**
* Specify the current page. It's necessary when remote is enabled
*/
page: number;
/**
* Specify the size per page. It's necessary when remote is enabled
*/
sizePerPage: number;
/**
* Total data size. It's necessary when remote is enabled
*/
totalSize: number;
/**
* first page will be 0, default is 1
*/
pageStartIndex: number;
/**
* the pagination bar size, default is 5
*/
paginationSize: number;
/**
* display pagination information
*/
showTotal: boolean;
/**
* A numeric array is also available: [5, 10]. the purpose of above example is custom the text
*/
sizePerPageList: number[] | Array<{ text: string; value: number }>;
/**
* hide the going to first and last page button
*/
withFirstAndLast: boolean;
/**
* always show the next and previous page button
*/
alwaysShowAllBtns: boolean;
/**
* the text of first page button
*/
firstPageText: string;
/**
* the text of previous page button
*/
prePageText: string;
/**
* the text of next page button
*/
nextPageText: string;
/**
* the text of last page button
*/
lastPageText: string;
/**
* the title of next page button
*/
nextPageTitle: string;
/**
* the title of previous page button
*/
prePageTitle: string;
/**
* the title of first page button
*/
firstPageTitle: string;
/**
* the title of last page button
*/
lastPageTitle: string;
/**
* hide the size per page dropdown
*/
hideSizePerPage: boolean;
/**
* hide pagination bar when only one page, default is false
*/
hidePageListOnlyOnePage: boolean;
/**
* callback function when page was changing
*/
onPageChange: (page: number, sizePerPage: number) => void;
/**
* callback function when page size was changing
*/
onSizePerPageChange: (page: number, sizePerPage: number) => void;
/**
* custom the pagination total
*/
paginationTotalRenderer: (from: number, to: number, size: number) => JSX.Element;
}>;
export interface SelectRowProps<T> {
mode: RowSelectionType;
clickToSelect?: boolean;
clickToExpand?: boolean;
clickToEdit?: boolean;
hideSelectAll?: boolean;
selected?: Array<number | string>;
onSelect?: (row: T, isSelected: boolean, rowIndex: number, e: SyntheticEvent) => void | boolean;
/**
* This callback function will be called when select/unselect all and it only work when you configure selectRow.mode as checkbox.
*/
onSelectAll?: (isSelect: boolean, rows: T[], e: React.SyntheticEvent) => void | number[];
style?: ((row: T, rowIndex: number) => CSSProperties | undefined) | CSSProperties;
classes?: ((row: T, rowIndex: number) => string | undefined) | string;
nonSelectable?: number[];
nonSelectableStyle?: ((row: T, rowIndex: number) => CSSProperties | undefined) | CSSProperties;
nonSelectableClasses?: ((row: T, rowIndex: number) => string | undefined) | string;
bgColor?: string;
hideSelectColumn?: boolean;
selectionRenderer?: ReactElement<{ mode: string; checked: boolean; disabled: boolean }>;
selectionHeaderRenderer?: ReactElement<{ mode: string; checked: boolean; indeterminate: boolean }>;
headerColumnStyle?: ((status: TableCheckboxStatus) => CSSProperties | undefined) | CSSProperties;
selectColumnStyle?:
| ((props: {
checked: boolean;
disabled: boolean;
rowIndex: number;
rowKey: string;
}) => CSSProperties | undefined)
| CSSProperties;
selectColumnPosition?: 'left' | 'right';
}
export interface BootstrapTableRef<T extends object = any> {
table: {
props: {
data: T[];
};
};
selectionContext?: {
selected?: any[];
};
rowExpandContext?: {
state: {
expanded?: any[];
};
};
paginationContext?: {
currPage: number;
currSizePerPage: number;
};
sortContext?: {
state: {
sortColumn: ColumnDescription<T>;
sortOrder: SortOrder;
};
};
filterContext?: {
currFilters: any;
};
cellEditContext?: {
startEditing: (rowIndex: number, columnIndex: number) => void;
};
}
export interface BootstrapTableProps<T extends object = any> {
/**
* Tells react-bootstrap-table2 which column is unique.
*/
keyField: string;
/**
* Provides data for your table. It accepts a single Array object.
*/
data: any[];
columns: ColumnDescription[];
bootstrap4?: boolean;
remote?: boolean | Partial<{ pagination: boolean; filter: boolean; sort: boolean; cellEdit: boolean }>;
noDataIndication?: () => JSX.Element | JSX.Element | string;
striped?: boolean;
bordered?: boolean;
hover?: boolean;
tabIndexCell?: boolean;
id?: string;
classes?: string;
headerClasses?: string;
bodyClasses?: string;
wrapperClasses?: string;
headerWrapperClasses?: string;
condensed?: boolean;
/**
* Same as HTML caption tag, you can set it as String or a React JSX.
*/
caption?: JSX.Element | string;
pagination?: { options?: PaginationOptions };
filter?: unknown;
cellEdit?: any;
selectRow?: SelectRowProps<T>;
expandRow?: ExpandRowProps<T>;
parentClassName?: string | ((isExpand: boolean, row: T, rowIndex: number) => string);
rowStyle?: ((row: T, rowIndex: number) => CSSProperties) | CSSProperties;
rowEvents?: RowEventHandlerProps;
rowClasses?: ((row: T, rowIndex: number) => string) | string;
filtersClasses?: string;
filterPosition?: FilterPosition;
footerClasses?: string;
defaultSorted?: [{ dataField: any; order: SortOrder }];
sort?: {
dataField?: any;
order: SortOrder;
sortFunc?: any;
sortCaret?: any;
};
defaultSortDirection?: SortOrder;
overlay?: any;
onTableChange?: TableChangeHandler<T>;
onSort?: any;
onFilter?: any;
onExternalFilter?: any;
/**
* This callback function will be called only when data size change by search/filter etc.
*/
onDataSizeChange?: (props: { dataSize: number }) => void;
search?: SearchProps<T> | boolean;
}
declare class BootstrapTable<T extends object = any> extends Component<BootstrapTableProps<T>> {}
export default BootstrapTable;
/**
* Search props
*
* Consult [documentation](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/search-props.html)
*/
export interface SearchProps<T> {
placeholder?: string;
searchText?: string;
defaultSearch?: string;
/* custom search method, return true if matched and false if not */
onColumnMatch?: (searchProps: { searchText: string; value: any; column: any; row: T }) => boolean;
}
export interface ExpandColumnRendererProps {
expanded: boolean;
rowKey: string;
expandable: boolean;
}
export interface ExpandHeaderColumnRenderer {
isAnyExpands: boolean;
}
export interface ExpandRowProps<T> {
renderer: (row: T, rowIndex: number) => JSX.Element;
expanded?: number[];
onExpand?: (row: T, isExpand: boolean, rowIndex: number, e: SyntheticEvent) => void;
onExpandAll: (isExpandAll: boolean, results: number[], e: SyntheticEvent) => void;
nonExpandable: number[];
showExpandColumn?: boolean;
onlyOneExpanding?: boolean;
expandByColumnOnly?: boolean;
expandColumnRenderer: ReactElement<ExpandColumnRendererProps>;
expandHeaderColumnRenderer: ReactElement<ExpandHeaderColumnRenderer>;
expandColumnPosition: 'left' | 'right';
className: string | ((isExpand: boolean, row: T, rowIndex: number) => string);
}
export type TableColumnFilterProps<FT = any, T extends object = any> = Partial<{
id: string;
/**
* custom the input placeholder
*/
placeholder: string;
/**
* custom classname on input
*/
className: string;
/**
* default filtering value
*/
defaultValue: any;
/**
* your custom styles on input
*/
style: React.CSSProperties;
/**
* how long will trigger filtering after user typing, default is 500 ms
*/
delay: number;
/*
* export filter function to allow users to access filter method externally.
*/
getFilter: (filter: FT) => void;
/**
* Register a listener which will be called when column filter being triggered. If you return an array value, react-bootstrap-table2 will adopt this value as the final filtered result.
*/
onFilter: (filterValue: FT) => void | T[];
}>;

View File

@@ -0,0 +1,182 @@
import * as React from 'react';
import { render } from 'react-dom';
import BootstrapTable, {
ColumnFormatter,
CellAlignment,
HeaderFormatter,
ColumnDescription,
RowSelectionType,
ROW_SELECT_SINGLE,
} from 'react-bootstrap-table-next';
interface Product {
id: number;
name: string;
price?: number;
quality?: number;
inStockStatus?: number;
sales?: number;
}
const products: Product[] = [
{
id: 1,
name: 'Item name 1',
price: 100,
},
{
id: 2,
name: 'Item name 2',
price: 100,
},
];
const priceHeaderFormatter: HeaderFormatter<Product> = (column, colIndex, components) => {
return (
<div>
{column.text}
{components.sortElement}
{components.filterElement}
</div>
);
};
const priceFormatter: ColumnFormatter<Product, { indexSquare: number }> = (cell, row, rowIndex) => {
return (
<span>
{rowIndex} - {cell}
</span>
);
};
const productColumns: Array<ColumnDescription<Product>> = [
{ dataField: 'id', align: 'center', sort: true, text: 'Product ID' },
{ dataField: 'name', align: 'center', sort: true, text: 'Product Name' },
{
isDummyField: true,
dataField: '',
sort: true,
text: 'Product Name',
},
{
dataField: 'price',
sort: true,
formatter: priceFormatter,
text: 'Product Price',
headerFormatter: priceHeaderFormatter,
},
/**
* test optional dataField for dummyFields
*/
{
isDummyField: true,
dataField: '',
sort: true,
formatter: priceFormatter,
text: 'Product Price',
headerFormatter: priceHeaderFormatter,
},
];
/**
* Basic table test with custom header and cell formatters
*/
render(
<BootstrapTable data={products} bootstrap4 striped={true} hover={true} keyField="id" columns={productColumns} />,
document.getElementById('app'),
);
/**
* Inline untyped columns test
*/
render(
<BootstrapTable
data={products}
bootstrap4
striped={true}
hover={true}
keyField="id"
columns={[
{ dataField: 'id', align: 'center', sort: true, text: 'Product ID' },
{ dataField: 'name', align: 'center', sort: true, text: 'Product Name' },
{
isDummyField: true,
dataField: '',
sort: true,
formatter: () => <span>Dummy Field</span>,
text: 'Dummy Columns',
},
{
dataField: 'price',
sort: true,
formatter: priceFormatter,
text: 'Product Price',
headerFormatter: priceHeaderFormatter,
},
/**
* test optional dataField for dummyFields
*/
{
isDummyField: true,
dataField: '',
sort: true,
formatter: priceFormatter,
text: 'Product Price',
headerFormatter: priceHeaderFormatter,
},
]}
/>,
document.getElementById('app'),
);
/**
* Basic table with custom data indicator and caption
*/
render(
<BootstrapTable
data={products}
bootstrap4
striped={true}
hover={true}
keyField="id"
noDataIndication={() => <div>No data available</div>}
caption={<span>Amazing table</span>}
columns={productColumns}
/>,
document.getElementById('app'),
);
/**
* Basic table with custom data indicator and caption
*/
render(
<BootstrapTable
data={products}
bootstrap4
keyField="id"
columns={productColumns}
selectRow={{
mode: ROW_SELECT_SINGLE,
}}
/>,
document.getElementById('app'),
);
/**
* Event handling table test
*/
render(
<BootstrapTable
data={products}
rowEvents={{
onClick: (e, row, rowIndex) => {
typeof row.inStockStatus === 'number';
},
onDoubleClick: (e, row, rowIndex) => {},
onMouseEnter: (e, row, rowIndex) => {},
onMouseLeave: (e, row, rowIndex) => {},
}}
keyField="id"
columns={productColumns}
/>,
document.getElementById('app'),
);

View File

@@ -0,0 +1,25 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6",
"dom"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"baseUrl": "../",
"jsx": "react",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"react-bootstrap-table-next-tests.tsx"
]
}

View File

@@ -0,0 +1 @@
{ "extends": "dtslint/dt.json" }

View File

@@ -0,0 +1,148 @@
// Type definitions for react-bootstrap-table2-filter 1.3
// Project: https://github.com/react-bootstrap-table/react-bootstrap-table2#readme
// Definitions by: Wlad Meixner <https://github.com/gosticks>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 3.0
// documentation taken from https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/table-props.html
import { TableColumnFilterProps, ColumnDescription } from 'react-bootstrap-table-next';
import { CSSProperties, SyntheticEvent } from 'react';
export enum FILTER_TYPES {
TEXT = 'TEXT',
SELECT = 'SELECT',
MULTISELECT = 'MULTISELECT',
NUMBER = 'NUMBER',
DATE = 'DATE',
}
/**
* Filter comparators used for table filters
*/
export enum Comparator {
LIKE = 'LIKE',
EQ = '=',
NE = '!=',
GT = '>',
GE = '>=',
LT = '<',
LE = '<=',
}
export type TextFilterProps<T extends object = any> = TableColumnFilterProps<TableColumnFilterProps, T> &
Partial<{
/**
* default is false, and true will only work when comparator is LIKE
*/
caseSensitive: boolean;
comparator: Comparator;
/**
* on filter element click event
*/
onClick?: (e: SyntheticEvent) => void;
}>;
/**
* text column filter
* @param props text filter options
*/
export function textFilter(props?: Partial<TextFilterProps>): TableColumnFilterProps;
/**
* select filter option type
*/
export type SelectFilterOptions = { [index: string]: string } | Array<{ value: number; label: string }>;
export type SelectFilterProps<T extends object = any> = TableColumnFilterProps<string, T> & {
options: SelectFilterOptions | ((column: ColumnDescription<T>) => SelectFilterOptions);
comparator?: Comparator;
/**
* When the default unset selection is hidden from dropdown
*/
withoutEmptyOption?: boolean;
};
/**
* single select column filter
* @param props Select filter options
*/
export function selectFilter(props: Partial<SelectFilterProps>): TableColumnFilterProps;
/**
* Datatype that can be used as the multiselect filter option
*/
export interface MultiSelectFilterOptions {
[index: string]: string;
}
/**
* Multi Select filter options
*/
export type MultiSelectFilterProps<T extends object = any> = TableColumnFilterProps<string, T> & {
options: MultiSelectFilterOptions | (() => MultiSelectFilterOptions);
comparator?: Comparator;
/**
* When set the default selection is hidden from dropdown
*/
withoutEmptyOption?: boolean;
};
/**
* multiSelectFilter adds multi select filtering to a column
* @param props filter options
*/
export function multiSelectFilter(props: Partial<MultiSelectFilterProps>): TableColumnFilterProps;
/**
* Number filter configuration options
*/
export type NumberFilterProps<T extends object = any> = TableColumnFilterProps<TableColumnFilterProps, T> & {
options?: number[];
comparators?: Comparator[];
/**
* When set to true comparator dropdown does not show a "no selection" option
*/
withoutEmptyComparatorOption?: boolean;
withoutEmptyNumberOption?: boolean;
comparatorClassName?: string;
numberClassName?: string;
comparatorStyle?: CSSProperties;
numberStyle?: CSSProperties;
defaultValue?: { number: number; comparator: Comparator };
};
export function numberFilter(props: Partial<NumberFilterProps>): TableColumnFilterProps;
/**
* Date filter options
*/
export interface DateFilter<T extends object = any> extends TableColumnFilterProps<TableColumnFilterProps, T> {
withoutEmptyComparatorOption?: boolean;
defaultValue?: {
date: Date;
comparator: Comparator;
};
comparator?: Comparator[];
comparatorClassName?: string;
dateClassName?: string;
comparatorStyle?: CSSProperties;
dateStyle?: CSSProperties;
}
export function dateFilter(props: DateFilter): TableColumnFilterProps;
/**
* Custom filter
*/
export interface CustomFilterProps {
type?: string | FILTER_TYPES;
comparator?: Comparator;
caseSensitive?: boolean;
}
export function customFilter(props: CustomFilterProps): TableColumnFilterProps;
/**
* declaration for table filter sub module
*/
declare function filterFactory(): unknown;
export default filterFactory;

View File

@@ -0,0 +1,267 @@
import * as React from 'react';
import BootstrapTable, { ColumnDescription, ColumnFormatter, HeaderFormatter } from 'react-bootstrap-table-next';
import filterFactory, {
Comparator,
multiSelectFilter,
numberFilter,
selectFilter,
textFilter,
} from 'react-bootstrap-table2-filter';
import { render } from 'react-dom';
// examples partially taken from https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/table-props.html
interface Product {
id: number;
name: string;
price?: number;
quality?: number;
inStockStatus?: number;
sales?: number;
}
const products: Product[] = [
{
id: 1,
name: 'Item name 1',
price: 100,
quality: 0,
},
{
id: 2,
name: 'Item name 2',
price: 100,
quality: 1,
},
];
const priceHeaderFormatter: HeaderFormatter<Product> = (column, colIndex, components) => {
return (
<div>
{column.text}
{components.sortElement}
{components.filterElement}
</div>
);
};
const priceFormatter: ColumnFormatter<Product, { indexSquare: number }> = (cell, row, rowIndex) => {
return (
<span>
{rowIndex} - {cell}
</span>
);
};
let priceFilter: any;
const productColumns: Array<ColumnDescription<Product>> = [
{ dataField: 'id', align: 'center', sort: true, text: 'Product ID' },
{ dataField: 'name', align: 'center', sort: true, text: 'Product Name' },
{
isDummyField: true,
dataField: '',
sort: true,
text: 'Product Name',
},
{
dataField: 'price',
sort: true,
formatter: priceFormatter,
text: 'Product Price',
headerFormatter: priceHeaderFormatter,
filter: numberFilter({
options: [2100, 2103, 2105], // if options defined, will render number select instead of number input
delay: 600, // how long will trigger filtering after user typing, default is 500 ms
placeholder: 'custom placeholder', // placeholder for number input
withoutEmptyComparatorOption: true, // dont render empty option for comparator
withoutEmptyNumberOption: true, // dont render empty option for number select if it is defined
comparators: [Comparator.EQ, Comparator.GT, Comparator.LT], // Custom the comparators
style: { display: 'inline-grid' }, // custom the style on number filter
className: 'custom-numberfilter-class', // custom the class on number filter
comparatorStyle: { backgroundColor: 'antiquewhite' }, // custom the style on comparator select
comparatorClassName: 'custom-comparator-class', // custom the class on comparator select
numberStyle: { backgroundColor: 'cadetblue', margin: '0px' }, // custom the style on number input/select
numberClassName: 'custom-number-class', // custom the class on ber input/select
defaultValue: { number: 2103, comparator: Comparator.GT }, // default value
getFilter: filter => {
// priceFilter was assigned once the component has been mounted.
priceFilter = filter;
},
onFilter: filterValue => {},
}),
},
{
isDummyField: true,
dataField: '',
sort: true,
formatter: priceFormatter,
text: 'Product Price',
headerFormatter: priceHeaderFormatter,
},
];
/**
* Number filter test
*/
render(
<BootstrapTable data={products} keyField="id" filter={filterFactory()} columns={productColumns} />,
document.getElementById('app'),
);
/**
* Options as Object
*/
const selectOptionsObject: { [index: number]: string } = {
0: 'good',
1: 'Bad',
2: 'unknown',
};
/**
* Options as Array
*/
const selectOptionsList = [
{ value: 0, label: 'good' },
{ value: 1, label: 'Bad' },
{ value: 2, label: 'unknown' },
];
/**
* Options as Function
*/
const selectOptionsCreator = (column: ColumnDescription<Product>) => [
{ value: 0, label: 'good' },
{ value: 1, label: 'Bad' },
{ value: 2, label: 'unknown' },
];
render(
<BootstrapTable
keyField="id"
data={products}
columns={[
{ dataField: 'id', align: 'center', sort: true, text: 'Product ID' },
{ dataField: 'name', align: 'center', sort: true, text: 'Product Name' },
{
dataField: 'quality',
text: 'Product Quailty',
// formatter: cell => selectOptionsObject[cell],
filter: selectFilter({
options: selectOptionsObject,
className: 'test-classname',
withoutEmptyOption: true,
defaultValue: 2,
comparator: Comparator.LIKE, // default is Comparator.EQ
style: { backgroundColor: 'pink' },
getFilter: filter => {
// qualityFilter was assigned once the component has been mounted.
},
onFilter: filterValue => {},
}),
},
]}
filter={filterFactory()}
/>,
document.getElementById('app'),
);
let qualityFilter: any;
render(
<BootstrapTable
keyField="id"
data={products}
columns={[
{ dataField: 'id', align: 'center', sort: true, text: 'Product ID' },
{
dataField: 'name',
formatter: cell => cell,
align: 'center',
sort: true,
text: 'Product Name',
},
{
dataField: 'quality',
text: 'Product Quailty',
formatter: (cell: number, row, rowIndex, formatExtraData) => selectOptionsObject[cell],
filter: multiSelectFilter({
options: selectOptionsObject,
className: 'test-classname',
withoutEmptyOption: true,
defaultValue: [0, 2],
comparator: Comparator.LIKE, // default is Comparator.EQ
style: { backgroundColor: 'pink' },
getFilter: filter => {
// qualityFilter was assigned once the component has been mounted.
qualityFilter = filter;
},
onFilter: filterValue => {
console.log(filterValue);
},
}),
},
]}
filter={filterFactory()}
/>,
document.getElementById('app'),
);
/**
* Single select column test
*/
const selectColumns = [
{
dataField: 'quality',
text: 'Product Quailty',
formatter: (cell: number) => {
const found = selectOptionsList.find(val => val.value === cell);
return found ? found.value : '';
},
filter: selectFilter({
options: selectOptionsList,
className: 'test-classname',
withoutEmptyOption: true,
defaultValue: 2,
comparator: Comparator.LIKE, // default is Comparator.EQ
style: { backgroundColor: 'pink' },
getFilter: filter => {
// qualityFilter was assigned once the component has been mounted.
qualityFilter = filter;
},
onFilter: filterValue => {},
}),
},
];
render(
<BootstrapTable keyField="id" data={products} columns={selectColumns} filter={filterFactory()} />,
document.getElementById('app'),
);
/**
* Text filter test
*/
const textColumns = [
{
dataField: 'id',
text: 'Product ID',
},
{
dataField: 'name',
text: 'Product Name',
filter: textFilter({
placeholder: 'My Custom PlaceHolder', // custom the input placeholder
className: 'my-custom-text-filter', // custom classname on input
defaultValue: 'test', // default filtering value
comparator: Comparator.EQ, // default is Comparator.LIKE
caseSensitive: true, // default is false, and true will only work when comparator is LIKE
style: { backgroundColor: 'yellow' }, // your custom inline styles on input
delay: 1000, // how long will trigger filtering after user typing, default is 500 ms
onClick: e => console.log(e),
}),
},
{
dataField: 'price',
text: 'Product Price',
filter: textFilter(),
},
];
<BootstrapTable keyField="id" data={products} columns={textColumns} filter={filterFactory()} />;

View File

@@ -0,0 +1,25 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6",
"dom"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"baseUrl": "../",
"jsx": "react",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"react-bootstrap-table2-filter-tests.tsx"
]
}

View File

@@ -0,0 +1 @@
{ "extends": "dtslint/dt.json" }

View File

@@ -0,0 +1,49 @@
// Type definitions for react-bootstrap-table2-paginator 2.1
// Project: https://github.com/react-bootstrap-table/react-bootstrap-table2#readme
// Definitions by: Wlad Meixner <https://github.com/gosticks>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 3.0
// documentation taken from https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/table-props.html
import { PaginationOptions, BootstrapTableProps } from 'react-bootstrap-table-next';
export interface PaginationCtxOptions {
options?: PaginationOptions;
}
/**
* declaration for table pagination sub module and factory
*/
declare function paginationFactory(options: PaginationOptions): PaginationCtxOptions;
export default paginationFactory;
interface PaginationChildProps extends PaginationOptions {
tableId?: string;
bootstrap4?: boolean;
}
/**
* Pagination context provider
*/
export function PaginationProvider(props: {
pagination?: PaginationOptions;
children: (childProps: {
paginationProps: PaginationChildProps;
paginationTableProps: BootstrapTableProps;
}) => React.ReactElement | null;
}): React.ReactElement | null;
export const PaginationTotalStandalone: React.FC<PaginationChildProps>;
export const PaginationListStandalone: React.FC<PaginationChildProps>;
export interface SizePerPageDropdownStandaloneProps extends PaginationChildProps {
open?: boolean;
hidden?: boolean;
btnContextual?: boolean;
variation?: 'dropdown' | 'dropup';
className?: string;
}
export const SizePerPageDropdownStandalone: React.FC<SizePerPageDropdownStandaloneProps>;

View File

@@ -0,0 +1,91 @@
import * as React from 'react';
import BootstrapTable, {
CellAlignment,
ColumnDescription,
HeaderFormatter,
ColumnFormatter,
} from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
import { render } from 'react-dom';
interface Product {
id: number;
name: string;
price?: number;
quality?: number;
inStockStatus?: number;
sales?: number;
}
const products: Product[] = [
{
id: 1,
name: 'Item name 1',
price: 100,
},
{
id: 2,
name: 'Item name 2',
price: 100,
},
];
const priceHeaderFormatter: HeaderFormatter<Product> = (column, colIndex, components) => {
return (
<div>
{column.text}
{components.sortElement}
{components.filterElement}
</div>
);
};
const priceFormatter: ColumnFormatter<Product, { indexSquare: number }> = (cell, row, rowIndex) => {
return (
<span>
{rowIndex} - {cell}
</span>
);
};
const productColumns: Array<ColumnDescription<Product>> = [
{ dataField: 'id', align: 'center', sort: true, text: 'Product ID' },
{ dataField: 'name', align: 'center', sort: true, text: 'Product Name' },
{
isDummyField: true,
dataField: '',
sort: true,
text: 'Product Name',
},
{
dataField: 'price',
sort: true,
formatter: priceFormatter,
text: 'Product Price',
headerFormatter: priceHeaderFormatter,
},
/**
* test optional dataField for dummyFields
*/
{
isDummyField: true,
dataField: '',
sort: true,
formatter: priceFormatter,
text: 'Product Price',
headerFormatter: priceHeaderFormatter,
},
];
/**
* pagination test
*/
render(
<BootstrapTable
data={products}
keyField="id"
pagination={paginationFactory({ sizePerPage: 10, page: 1 })}
columns={productColumns}
/>,
document.getElementById('app'),
);

View File

@@ -0,0 +1,25 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6",
"dom"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"baseUrl": "../",
"jsx": "react",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"react-bootstrap-table2-paginator-tests.tsx"
]
}

View File

@@ -0,0 +1 @@
{ "extends": "dtslint/dt.json" }

View File

@@ -0,0 +1,120 @@
// Type definitions for react-bootstrap-table2-toolkit 2.1
// Project: https://github.com/react-bootstrap-table/react-bootstrap-table2#readme
// Definitions by: Wlad Meixner <https://github.com/gosticks>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 3.0
// documentation taken from https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/table-props.html
import { CSSProperties, ReactNode } from 'react';
import { ColumnDescription } from 'react-bootstrap-table-next';
/**
* declaration for table toolkit sub module
*/
export interface InjectedSearchProps {
searchText: string;
onSearch: (val: string) => void;
onClear: () => void;
}
export interface SearchMatchProps<T extends object = any> {
searchText: string;
value: string;
column: ColumnDescription<T>;
row: T;
}
export interface TableSearchProps<T extends object = any> {
searchFormatted?: boolean;
defaultSearch?: string;
placeholder?: string;
onColumnMatch?: (props: SearchMatchProps<T>) => void;
customMatchFunc?: (props: SearchMatchProps<T>) => boolean;
}
export interface TableToolkitProps<T extends object = any> {
bootstrap4?: boolean;
search?: TableSearchProps<T> | boolean;
keyField: keyof T | string;
data: T[];
ref?: any;
columns: Array<ColumnDescription<T>>;
children: (props: ToolkitContextType) => JSX.Element;
}
export interface ToolkitContextType {
searchProps: InjectedSearchProps;
csvProps: {
onExport: () => void;
};
columnToggleProps: {
columns: ColumnDescription[];
/**
* array of toggled columns
*/
toggles: boolean[];
onColumnToggle: (dataField: string) => void;
};
baseProps: {
/**
* table key field
*/
keyField: any;
columns: ColumnDescription[];
data: any[];
bootstrap4?: boolean;
};
}
export interface ToggleListProps {
columns: ColumnDescription[];
/**
* array of toggled columns
*/
toggles: boolean[];
onColumnToggle: (dataField: string) => void;
btnClassName?: string;
className?: string;
contextual?: string;
}
export namespace ColumnToggle {
function ToggleList(props: ToggleListProps): React.ReactElement | null;
}
export interface ExportCSVButtonProps {
children: ReactNode;
onExport: () => void;
style?: CSSProperties;
className?: string;
}
export namespace CSVExport {
function ToggleList(props: ExportCSVButtonProps): React.ReactElement | null;
}
export interface SearchBarProps {
onSearch: (searchText: string) => void;
className?: string;
placeholder?: string;
style?: CSSProperties;
delay?: number;
searchText?: string;
tableId?: string;
}
export interface ClearSearchButtonProps {
onClear?: () => void;
className?: string;
text?: string;
}
export namespace Search {
function SearchBar(props: SearchBarProps): React.ReactElement | null;
function ClearSearchButton(props: ExportCSVButtonProps): React.ReactElement | null;
}
export const ToolkitContext: React.Context<ToolkitContextType>;
declare function ToolkitProvider(props: TableToolkitProps): React.ReactElement | null;
export default ToolkitProvider;

View File

@@ -0,0 +1,104 @@
import * as React from 'react';
import BootstrapTable, {
CellAlignment,
ColumnDescription,
HeaderFormatter,
ColumnFormatter,
} from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
import { render } from 'react-dom';
import ToolkitProvider, { InjectedSearchProps } from 'react-bootstrap-table2-toolkit';
interface Product {
id: number;
name: string;
price?: number;
quality?: number;
inStockStatus?: number;
sales?: number;
}
const products: Product[] = [
{
id: 1,
name: 'Item name 1',
price: 100,
},
{
id: 2,
name: 'Item name 2',
price: 100,
},
];
const priceHeaderFormatter: HeaderFormatter<Product> = (column, colIndex, components) => {
return (
<div>
{column.text}
{components.sortElement}
{components.filterElement}
</div>
);
};
const priceFormatter: ColumnFormatter<Product, { indexSquare: number }> = (cell, row, rowIndex) => {
return (
<span>
{rowIndex} - {cell}
</span>
);
};
const productColumns: Array<ColumnDescription<Product>> = [
{ dataField: 'id', align: 'center', sort: true, text: 'Product ID' },
{ dataField: 'name', align: 'center', sort: true, text: 'Product Name' },
{
isDummyField: true,
dataField: '',
sort: true,
text: 'Product Name',
},
{
dataField: 'price',
sort: true,
formatter: priceFormatter,
text: 'Product Price',
headerFormatter: priceHeaderFormatter,
},
/**
* test optional dataField for dummyFields
*/
{
isDummyField: true,
dataField: '',
sort: true,
formatter: priceFormatter,
text: 'Product Price',
headerFormatter: priceHeaderFormatter,
},
];
/**
* Toolkit with custom search test test
*/
const CustomSearch = (props: InjectedSearchProps) => {
return (
<span>
<input value={props.searchText} onChange={e => props.onSearch(e.currentTarget.value)} />
<button onClick={props.onClear}>Clear Search</button>
</span>
);
};
render(
<ToolkitProvider data={products} keyField="id" columns={productColumns}>
{({ baseProps, searchProps }) => (
<>
<CustomSearch {...searchProps} />
<BootstrapTable {...baseProps} pagination={paginationFactory({ sizePerPage: 10, page: 1 })} />
</>
)}
</ToolkitProvider>,
document.getElementById('app'),
);

View File

@@ -0,0 +1,25 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6",
"dom"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"baseUrl": "../",
"jsx": "react",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"react-bootstrap-table2-toolkit-tests.tsx"
]
}

View File

@@ -0,0 +1 @@
{ "extends": "dtslint/dt.json" }