@chumsinc/sortable-tables 2.1.2 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -1
- package/dist/DataTable.d.ts +1 -1
- package/dist/DataTableCell.d.ts +172 -172
- package/dist/DataTableCols.d.ts +5 -0
- package/dist/DataTableHead.d.ts +2 -2
- package/dist/DataTableRow.d.ts +1 -1
- package/dist/DataTableTBody.d.ts +1 -1
- package/dist/DataTableWithContext.d.ts +2 -0
- package/dist/RowsPerPage.d.ts +0 -1
- package/dist/SortableTable.d.ts +1 -1
- package/dist/SortableTableHead.d.ts +1 -1
- package/dist/SortableTableWithContext.d.ts +2 -0
- package/dist/TableProvider.d.ts +17 -0
- package/dist/index.cjs.js +18 -12
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.es.js +351 -268
- package/dist/index.es.js.map +1 -1
- package/dist/types.d.ts +14 -16
- package/eslint.config.mjs +3 -3
- package/package.json +6 -4
- package/src/DataTable.tsx +5 -33
- package/src/DataTableCell.tsx +5 -5
- package/src/DataTableCols.tsx +25 -0
- package/src/DataTableHead.tsx +6 -5
- package/src/DataTableRow.tsx +5 -4
- package/src/DataTableTBody.tsx +0 -2
- package/src/DataTableTH.tsx +8 -7
- package/src/DataTableWithContext.tsx +41 -0
- package/src/RowsPerPage.tsx +4 -5
- package/src/SortableTable.tsx +5 -31
- package/src/SortableTableHead.tsx +12 -11
- package/src/SortableTableTH.tsx +7 -4
- package/src/SortableTableWithContext.tsx +44 -0
- package/src/Table.tsx +2 -2
- package/src/TablePagination.tsx +3 -3
- package/src/TableProvider.tsx +77 -0
- package/src/index.tsx +10 -2
- package/src/types.ts +18 -20
- package/test/TableColumnsHandler.tsx +28 -0
- package/test/TestTable.tsx +15 -37
- package/test/tableFields.tsx +44 -0
- package/vite.config.ts +1 -2
package/src/SortableTable.tsx
CHANGED
|
@@ -1,43 +1,17 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import classNames from "classnames";
|
|
3
|
-
import SortableTableHead from "./SortableTableHead";
|
|
4
|
-
import DataTableTBody from "./DataTableTBody";
|
|
5
2
|
import type {SortableTableProps} from "./types";
|
|
6
|
-
import
|
|
3
|
+
import TableProvider from "./TableProvider";
|
|
4
|
+
import SortableTableWithContext from "./SortableTableWithContext";
|
|
7
5
|
|
|
8
6
|
|
|
9
7
|
function SortableTable<T = unknown>({
|
|
10
8
|
fields,
|
|
11
|
-
data,
|
|
12
|
-
currentSort,
|
|
13
|
-
onChangeSort,
|
|
14
|
-
keyField,
|
|
15
|
-
size = '',
|
|
16
|
-
sticky,
|
|
17
|
-
rowClassName,
|
|
18
|
-
renderRow,
|
|
19
|
-
onSelectRow,
|
|
20
|
-
selected = '',
|
|
21
|
-
className = '',
|
|
22
|
-
tfoot,
|
|
23
|
-
children,
|
|
24
9
|
...rest
|
|
25
10
|
}: SortableTableProps<T>) {
|
|
26
|
-
const tableClassName = classNames('table', className, {
|
|
27
|
-
[`table-${size}`]: !!size,
|
|
28
|
-
})
|
|
29
|
-
|
|
30
11
|
return (
|
|
31
|
-
<
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
<DataTableTBody fields={fields} data={data} keyField={keyField} rowClassName={rowClassName}
|
|
35
|
-
renderRow={renderRow}
|
|
36
|
-
onSelectRow={onSelectRow} selected={selected}/>
|
|
37
|
-
)}
|
|
38
|
-
{children}
|
|
39
|
-
{tfoot}
|
|
40
|
-
</Table>
|
|
12
|
+
<TableProvider initialFields={fields}>
|
|
13
|
+
<SortableTableWithContext {...rest}/>
|
|
14
|
+
</TableProvider>
|
|
41
15
|
)
|
|
42
16
|
}
|
|
43
17
|
|
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import SortableTableTH from "./SortableTableTH";
|
|
3
|
-
import classNames from "classnames";
|
|
4
3
|
import type {SortableTableHeadProps} from "./types";
|
|
4
|
+
import clsx from "clsx";
|
|
5
|
+
import {useTableFields} from "./TableProvider";
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
function SortableTableHead<T = unknown>({
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
currentSort,
|
|
10
|
+
onChangeSort,
|
|
11
|
+
}: SortableTableHeadProps<T>) {
|
|
12
|
+
const fields = useTableFields<T>()
|
|
12
13
|
const {field, ascending} = currentSort;
|
|
13
14
|
return (
|
|
14
15
|
<thead>
|
|
15
16
|
<tr>
|
|
16
17
|
{fields.map((tableField, index) => (
|
|
17
18
|
<SortableTableTH<T> key={index} field={tableField}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
sorted={field === tableField.field} ascending={ascending}
|
|
20
|
+
className={clsx(
|
|
21
|
+
typeof tableField.className === 'function'
|
|
22
|
+
? {[`text-${tableField.align}`]: !!tableField.align}
|
|
23
|
+
: tableField.className
|
|
24
|
+
)} onClick={onChangeSort}/>
|
|
24
25
|
))}
|
|
25
26
|
</tr>
|
|
26
27
|
</thead>
|
package/src/SortableTableTH.tsx
CHANGED
|
@@ -3,6 +3,7 @@ import classNames from "classnames";
|
|
|
3
3
|
import DataTableTH from "./DataTableTH";
|
|
4
4
|
import type {SortableTableTHProps, UIFlexAlign} from "./types";
|
|
5
5
|
import styled from '@emotion/styled';
|
|
6
|
+
import clsx from "clsx";
|
|
6
7
|
|
|
7
8
|
const flexJustifyContent = (align?: UIFlexAlign) => {
|
|
8
9
|
if (!align) {
|
|
@@ -25,12 +26,14 @@ const FieldTitle = styled.div<FieldTitleProps>`
|
|
|
25
26
|
width: 100%;
|
|
26
27
|
flex-direction: ${props => props.align === 'end' ? 'row-reverse' : 'row'};
|
|
27
28
|
justify-content: ${props => flexJustifyContent(props.align)};
|
|
29
|
+
|
|
28
30
|
.sort-icon {
|
|
29
31
|
flex-grow: ${props => props.align === 'end' ? '1' : '0'};
|
|
30
32
|
opacity: ${props => props.sorted ? 1 : 0};
|
|
31
33
|
}
|
|
34
|
+
|
|
32
35
|
&:hover .sort-icon {
|
|
33
|
-
color: ${props => props.sorted ? 'unset' : 'var(--bs-primary)'}
|
|
36
|
+
color: ${props => props.sorted ? 'unset' : 'var(--bs-primary)'};
|
|
34
37
|
opacity: 0.75;
|
|
35
38
|
transition: opacity 0.2s;
|
|
36
39
|
}
|
|
@@ -48,7 +51,7 @@ function SortableTableTH<T = unknown>({
|
|
|
48
51
|
}
|
|
49
52
|
|
|
50
53
|
const {className: _thClassName, ...thProps} = field.thProps ?? {};
|
|
51
|
-
const thClassName =
|
|
54
|
+
const thClassName = clsx(
|
|
52
55
|
className,
|
|
53
56
|
_thClassName,
|
|
54
57
|
{[`text-${field.align}`]: !!field.align}
|
|
@@ -64,10 +67,10 @@ function SortableTableTH<T = unknown>({
|
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
return (
|
|
67
|
-
<th {...thProps} className={
|
|
70
|
+
<th {...thProps} className={clsx("sortable", thClassName)} scope="col" onClick={clickHandler}>
|
|
68
71
|
<FieldTitle sorted={sorted} align={field.align}>
|
|
69
72
|
<div className="field-title">{field.title}</div>
|
|
70
|
-
<div className={
|
|
73
|
+
<div className={clsx('me-1 sort-icon', iconClassName)}/>
|
|
71
74
|
</FieldTitle>
|
|
72
75
|
</th>
|
|
73
76
|
)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type {SortableTableProps} from "./types";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
import Table from "./Table";
|
|
4
|
+
import {DataTableCols, DataTableTBody} from "./index";
|
|
5
|
+
import SortableTableHead from "./SortableTableHead";
|
|
6
|
+
import React from "react";
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export default function SortableTableWithContext<T = unknown>({
|
|
10
|
+
className,
|
|
11
|
+
size,
|
|
12
|
+
responsive,
|
|
13
|
+
sticky,
|
|
14
|
+
data,
|
|
15
|
+
keyField,
|
|
16
|
+
rowClassName,
|
|
17
|
+
renderRow,
|
|
18
|
+
onSelectRow,
|
|
19
|
+
selected,
|
|
20
|
+
tableHeadProps,
|
|
21
|
+
children,
|
|
22
|
+
tfoot,
|
|
23
|
+
currentSort,
|
|
24
|
+
onChangeSort,
|
|
25
|
+
...rest
|
|
26
|
+
}: Omit<SortableTableProps<T>, 'fields'>) {
|
|
27
|
+
const tableClassName = clsx('table', className, {
|
|
28
|
+
[`table-${size}`]: !!size,
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<Table className={tableClassName} responsive={responsive} sticky={sticky} {...rest}>
|
|
33
|
+
<DataTableCols/>
|
|
34
|
+
<SortableTableHead currentSort={currentSort} onChangeSort={onChangeSort} {...tableHeadProps}/>
|
|
35
|
+
{!!data.length && (
|
|
36
|
+
<DataTableTBody data={data} keyField={keyField} rowClassName={rowClassName}
|
|
37
|
+
renderRow={renderRow}
|
|
38
|
+
onSelectRow={onSelectRow} selected={selected}/>
|
|
39
|
+
)}
|
|
40
|
+
{children}
|
|
41
|
+
{tfoot}
|
|
42
|
+
</Table>
|
|
43
|
+
)
|
|
44
|
+
}
|
package/src/Table.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, {TableHTMLAttributes} from 'react';
|
|
2
2
|
import styled from "@emotion/styled";
|
|
3
3
|
import type {DataTableProps} from "./types";
|
|
4
|
-
import
|
|
4
|
+
import clsx from "clsx";
|
|
5
5
|
|
|
6
6
|
export type StyledTableProps = TableHTMLAttributes<HTMLTableElement> & Pick<DataTableProps, 'sticky' | 'responsive'>
|
|
7
7
|
|
|
@@ -28,7 +28,7 @@ export default React.forwardRef<HTMLTableElement, StyledTableProps>(
|
|
|
28
28
|
...rest
|
|
29
29
|
}, ref) {
|
|
30
30
|
if (responsive) {
|
|
31
|
-
const _className =
|
|
31
|
+
const _className = clsx(className, {
|
|
32
32
|
'table-responsive': responsive === true,
|
|
33
33
|
[`table-responsive-${responsive}`]: responsive !== true,
|
|
34
34
|
})
|
package/src/TablePagination.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import RowsPerPage from "./RowsPerPage";
|
|
3
|
-
import classNames from "classnames";
|
|
4
3
|
import type {TablePaginationProps} from "./types";
|
|
4
|
+
import clsx from "clsx";
|
|
5
5
|
|
|
6
6
|
function TablePagination({
|
|
7
7
|
page,
|
|
@@ -20,10 +20,10 @@ function TablePagination({
|
|
|
20
20
|
const last = Math.min(page * rowsPerPage + rowsPerPage, count);
|
|
21
21
|
const lastPage = rowsPerPage === 0 ? 0 : Math.floor((count - 1) / rowsPerPage);
|
|
22
22
|
|
|
23
|
-
const buttonClassName =
|
|
23
|
+
const buttonClassName = clsx("btn btn-link", {[`btn-${size}`]: !!size});
|
|
24
24
|
|
|
25
25
|
return (
|
|
26
|
-
<div className={
|
|
26
|
+
<div className={clsx("row g-3 justify-content-end", className)} {...rest}>
|
|
27
27
|
{!!rowsPerPageProps && (
|
|
28
28
|
<div className="col-auto">
|
|
29
29
|
<RowsPerPage {...rowsPerPageProps} value={rowsPerPage} size={size}/>
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {createContext, ReactNode, useCallback, useContext, useMemo, useState} from "react";
|
|
2
|
+
import {DataTableField} from "./types";
|
|
3
|
+
|
|
4
|
+
/* eslint-disable react-refresh/only-export-components */
|
|
5
|
+
|
|
6
|
+
export interface TableContextData<T = unknown> {
|
|
7
|
+
fields: DataTableField<T>[];
|
|
8
|
+
setFields: (next: DataTableField<T>[] | ((prev: DataTableField<T>[]) => DataTableField<T>[])) => void;
|
|
9
|
+
updateField: (key: string | number, arg: Partial<DataTableField<T>>) => void;
|
|
10
|
+
getField: (key: string | number) => DataTableField<T> | undefined;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const DataTableContext = createContext<TableContextData<unknown> | null>(null)
|
|
14
|
+
|
|
15
|
+
export interface TableProviderProps<T = unknown> {
|
|
16
|
+
initialFields: DataTableField<T>[];
|
|
17
|
+
children: ReactNode;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default function TableProvider<T = unknown>({children, initialFields = []}: TableProviderProps<T>) {
|
|
21
|
+
const [fields, setFieldsState] = useState<DataTableField<T>[]>(initialFields);
|
|
22
|
+
|
|
23
|
+
const setFields = useCallback((fields: DataTableField<T>[] | ((prev: DataTableField<T>[]) => DataTableField<T>[])) => {
|
|
24
|
+
setFieldsState(fields)
|
|
25
|
+
}, []);
|
|
26
|
+
const updateField = useCallback((key: string | number, arg: Partial<DataTableField<T>>) => {
|
|
27
|
+
const nextState = fields.map(field => {
|
|
28
|
+
if (field.id === key) {
|
|
29
|
+
return {...field, ...arg}
|
|
30
|
+
}
|
|
31
|
+
return field;
|
|
32
|
+
});
|
|
33
|
+
setFieldsState(nextState);
|
|
34
|
+
}, [fields])
|
|
35
|
+
|
|
36
|
+
const getField = useCallback((key: string | number) => fields.find(field => field.id === key), [fields]);
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
const value = useMemo<TableContextData<T>>(
|
|
40
|
+
() => ({
|
|
41
|
+
fields, setFields, updateField, getField
|
|
42
|
+
}),
|
|
43
|
+
[fields, setFields, updateField, getField]
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<DataTableContext.Provider value={value as unknown as TableContextData<unknown>}>
|
|
48
|
+
{children}
|
|
49
|
+
</DataTableContext.Provider>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
export function useTableContext<T = unknown>() {
|
|
55
|
+
const context = useContext(DataTableContext) as TableContextData<T>;
|
|
56
|
+
if (!context) {
|
|
57
|
+
throw new Error('useTableContext must be used within a FieldsProvider');
|
|
58
|
+
}
|
|
59
|
+
return context;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function useTableFields<T = unknown>() {
|
|
63
|
+
return useTableContext<T>().fields;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function useField<T = unknown>(key: string | number): DataTableField<T> | null {
|
|
67
|
+
const context = useContext(DataTableContext) as TableContextData<T>;
|
|
68
|
+
if (!context) {
|
|
69
|
+
throw new Error('useTableContext must be used within a FieldsProvider');
|
|
70
|
+
}
|
|
71
|
+
const field = context.fields.find(field => field.id === key);
|
|
72
|
+
return field ?? null
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function useHasTableFieldsContext() {
|
|
76
|
+
return useContext(DataTableContext) !== null;
|
|
77
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/* eslint-disable react-refresh/only-export-components */
|
|
2
|
+
|
|
1
3
|
export {default as DataTable} from './DataTable';
|
|
2
4
|
export {default as DataTableRow} from './DataTableRow';
|
|
3
5
|
export {default as DataTableTBody} from './DataTableTBody';
|
|
@@ -5,10 +7,15 @@ export {default as DataTableTH} from './DataTableTH';
|
|
|
5
7
|
export {default as SortableTable} from './SortableTable';
|
|
6
8
|
export {default as SortableTableHead} from './SortableTableHead';
|
|
7
9
|
export {default as SortableTableTH} from './SortableTableTH';
|
|
8
|
-
export {default as RowsPerPage
|
|
10
|
+
export {default as RowsPerPage} from './RowsPerPage';
|
|
9
11
|
export {default as TablePagination} from './TablePagination';
|
|
12
|
+
export {default as DataTableCols} from './DataTableCols'
|
|
13
|
+
export {default as DataTableWithContext} from './DataTableWithContext'
|
|
14
|
+
export {default as SortableTableWithContext} from './SortableTableWithContext'
|
|
15
|
+
export {default as DataTableProvider} from './TableProvider'
|
|
16
|
+
export {useTableContext, useTableFields, useHasTableFieldsContext, useField} from './TableProvider'
|
|
17
|
+
export type {TableContextData, TableProviderProps} from './TableProvider'
|
|
10
18
|
export type {
|
|
11
|
-
DataTableHeadProps,
|
|
12
19
|
DataTableField,
|
|
13
20
|
DataTableTHProps,
|
|
14
21
|
DataTableClassNames,
|
|
@@ -27,3 +34,4 @@ export type {
|
|
|
27
34
|
UITableSize,
|
|
28
35
|
DataTableCellProps
|
|
29
36
|
} from './types';
|
|
37
|
+
|
package/src/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, {type HTMLAttributes, type MouseEvent, type ReactNode, type TableHTMLAttributes} from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import type {ClassValue} from "clsx";
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
export interface SortProps<T = unknown> {
|
|
@@ -12,8 +12,8 @@ export type UITableSize = UISize | 'xs';
|
|
|
12
12
|
|
|
13
13
|
export type DataTableClassNames<T = unknown> =
|
|
14
14
|
string
|
|
15
|
-
|
|
|
16
|
-
| ((row: T) => (string |
|
|
15
|
+
| ClassValue
|
|
16
|
+
| ((row: T) => (string | ClassValue));
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
export type UIFlexAlign = 'start' | 'end' | 'center' | 'baseline' | 'stretch';
|
|
@@ -28,13 +28,14 @@ export interface DataTableField<T = unknown> {
|
|
|
28
28
|
className?: DataTableClassNames<T>;
|
|
29
29
|
colSpan?: number;
|
|
30
30
|
thProps?: Omit<DataTableTHProps<T>, 'field'>;
|
|
31
|
-
cellProps?: TableHTMLAttributes<HTMLTableCellElement
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
export interface SortableTableField<T = unknown> extends DataTableField<T> {
|
|
31
|
+
cellProps?: TableHTMLAttributes<HTMLTableCellElement>;
|
|
32
|
+
collapse?: boolean;
|
|
33
|
+
colClassName?: string;
|
|
35
34
|
sortable?: boolean;
|
|
36
35
|
}
|
|
37
36
|
|
|
37
|
+
export type SortableTableField<T = unknown> = DataTableField<T>;
|
|
38
|
+
|
|
38
39
|
export interface DataTableProps<T = unknown> extends TableHTMLAttributes<HTMLTableElement> {
|
|
39
40
|
fields: DataTableField<T>[];
|
|
40
41
|
data: T[];
|
|
@@ -47,7 +48,7 @@ export interface DataTableProps<T = unknown> extends TableHTMLAttributes<HTMLTab
|
|
|
47
48
|
onSelectRow?: (row: T, ev?: MouseEvent<HTMLTableRowElement>) => void;
|
|
48
49
|
selected?: string | number | ((row: T) => boolean);
|
|
49
50
|
tfoot?: React.ReactElement<HTMLTableSectionElement>;
|
|
50
|
-
tableHeadProps?:
|
|
51
|
+
tableHeadProps?: TableHTMLAttributes<HTMLTableSectionElement>;
|
|
51
52
|
children?: ReactNode;
|
|
52
53
|
}
|
|
53
54
|
|
|
@@ -55,7 +56,7 @@ export interface DataTableCellProps<T = unknown> extends Omit<TableHTMLAttribute
|
|
|
55
56
|
field: DataTableField<T>;
|
|
56
57
|
row: T;
|
|
57
58
|
as?: 'td' | 'th',
|
|
58
|
-
className?: string |
|
|
59
|
+
className?: string | ClassValue;
|
|
59
60
|
children?: React.ReactNode;
|
|
60
61
|
}
|
|
61
62
|
|
|
@@ -63,12 +64,7 @@ export interface DataTableTHProps<T = unknown> extends Omit<DataTableCellProps<T
|
|
|
63
64
|
as?: 'th',
|
|
64
65
|
}
|
|
65
66
|
|
|
66
|
-
export interface DataTableHeadProps<T = unknown> extends TableHTMLAttributes<HTMLTableSectionElement> {
|
|
67
|
-
fields: DataTableField<T>[];
|
|
68
|
-
}
|
|
69
|
-
|
|
70
67
|
export interface DataTableTBodyProps<T = unknown> extends TableHTMLAttributes<HTMLTableSectionElement> {
|
|
71
|
-
fields: DataTableField<T>[];
|
|
72
68
|
data: T[];
|
|
73
69
|
keyField: keyof T | ((row: T) => string | number);
|
|
74
70
|
rowClassName?: DataTableClassNames<T>;
|
|
@@ -79,28 +75,26 @@ export interface DataTableTBodyProps<T = unknown> extends TableHTMLAttributes<HT
|
|
|
79
75
|
}
|
|
80
76
|
|
|
81
77
|
export interface DataTableRowProps<T = unknown> extends Omit<TableHTMLAttributes<HTMLTableRowElement>, 'onClick'> {
|
|
82
|
-
rowClassName?: string |
|
|
78
|
+
rowClassName?: string | ClassValue | ((row: T) => string | ClassValue);
|
|
83
79
|
selected?: boolean;
|
|
84
|
-
fields: DataTableField<T>[];
|
|
85
80
|
row: T;
|
|
86
81
|
trRef?: React.Ref<HTMLTableRowElement>;
|
|
87
82
|
onClick?: (row: T, ev?: MouseEvent<HTMLTableRowElement>) => void;
|
|
88
83
|
}
|
|
89
84
|
|
|
90
85
|
export interface SortableTableProps<T = unknown> extends DataTableProps<T> {
|
|
91
|
-
fields:
|
|
86
|
+
fields: DataTableField<T>[];
|
|
92
87
|
currentSort: SortProps<T>;
|
|
93
88
|
onChangeSort: (sort: SortProps<T>) => void;
|
|
94
89
|
}
|
|
95
90
|
|
|
96
|
-
export interface SortableTableHeadProps<T = unknown> extends
|
|
91
|
+
export interface SortableTableHeadProps<T = unknown> extends TableHTMLAttributes<HTMLTableSectionElement> {
|
|
97
92
|
currentSort: SortProps<T>;
|
|
98
|
-
fields: SortableTableField<T>[];
|
|
99
93
|
onChangeSort: (sort: SortProps<T>) => void;
|
|
100
94
|
}
|
|
101
95
|
|
|
102
96
|
export interface SortableTableTHProps<T = unknown> extends Omit<DataTableTHProps<T>, 'onClick'> {
|
|
103
|
-
field:
|
|
97
|
+
field: DataTableField<T>;
|
|
104
98
|
sorted?: boolean;
|
|
105
99
|
ascending?: boolean;
|
|
106
100
|
onClick: (sort: SortProps<T>) => void;
|
|
@@ -126,3 +120,7 @@ export interface TablePaginationProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
126
120
|
rowsPerPageProps?: Omit<RowsPerPageProps, 'value'>;
|
|
127
121
|
}
|
|
128
122
|
|
|
123
|
+
|
|
124
|
+
export interface DataTableColProps<T = unknown> extends TableHTMLAttributes<HTMLTableSectionElement> {
|
|
125
|
+
fields: DataTableField<T>[];
|
|
126
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {useTableContext, useTableSort} from "../src";
|
|
2
|
+
import React, {useCallback, useId} from "react";
|
|
3
|
+
import {ProductLine} from "./data";
|
|
4
|
+
|
|
5
|
+
export default function TableColumnsHandler() {
|
|
6
|
+
const {updateField, getField} = useTableContext<ProductLine>();
|
|
7
|
+
const [collapse, setCollapse] = React.useState<boolean>(getField('ProductLineDesc')?.collapse ?? false);
|
|
8
|
+
const {sort} = useTableSort();
|
|
9
|
+
const id = useId();
|
|
10
|
+
|
|
11
|
+
const toggleFieldCollapse = useCallback((key: string, next: boolean) => {
|
|
12
|
+
console.debug('toggleFieldVisibility', key, next);
|
|
13
|
+
updateField(key, {collapse: next})
|
|
14
|
+
setCollapse(next);
|
|
15
|
+
}, [updateField]);
|
|
16
|
+
|
|
17
|
+
const handleVisibleChange = (ev: React.ChangeEvent<HTMLInputElement>) => {
|
|
18
|
+
toggleFieldCollapse('ProductLineDesc', ev.target.checked);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<div style={{display: 'flex', alignItems: 'center', justifyContent: 'flex-start', gap: '1rem'}}>
|
|
23
|
+
<input type="checkbox" checked={collapse} id={id} onChange={handleVisibleChange}/>
|
|
24
|
+
<label htmlFor={id}>Hide Description</label>
|
|
25
|
+
<code>{JSON.stringify(sort)}</code>
|
|
26
|
+
</div>
|
|
27
|
+
)
|
|
28
|
+
}
|
package/test/TestTable.tsx
CHANGED
|
@@ -1,33 +1,12 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
import {ProductLine, productLines
|
|
3
|
-
import {
|
|
1
|
+
import React, {useState} from 'react';
|
|
2
|
+
import {ProductLine, productLines} from './data'
|
|
3
|
+
import {SortableTableWithContext, SortProps} from "../src";
|
|
4
4
|
import TablePagination from "../src/TablePagination";
|
|
5
|
+
import TableProvider from "../src/TableProvider";
|
|
6
|
+
import TableColumnsHandler from "./TableColumnsHandler";
|
|
7
|
+
import {tableFields} from "./tableFields";
|
|
8
|
+
|
|
5
9
|
|
|
6
|
-
const fields: SortableTableField<ProductLine>[] = [
|
|
7
|
-
{field: 'ProductLine', title: 'Prod Line', sortable: true, as: 'th'},
|
|
8
|
-
{field: 'ProductLineDesc', title: 'Description', sortable: true},
|
|
9
|
-
{
|
|
10
|
-
field: 'ProductType',
|
|
11
|
-
title: 'Description',
|
|
12
|
-
sortable: true,
|
|
13
|
-
render: (row) => <span className="badge bg-info">{row.ProductType}</span>,
|
|
14
|
-
align: 'center'
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
field: 'Valuation',
|
|
18
|
-
title: 'Valuation',
|
|
19
|
-
sortable: true,
|
|
20
|
-
render: (row) => <span className="badge bg-secondary">{row.Valuation}</span>,
|
|
21
|
-
align: 'center'
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
field: 'ExplodeKitItems',
|
|
25
|
-
title: 'Explode Kit Items?',
|
|
26
|
-
sortable: true,
|
|
27
|
-
render: (row) => <span className="badge bg-primary">{row.ExplodeKitItems}</span>,
|
|
28
|
-
align: 'end'
|
|
29
|
-
},
|
|
30
|
-
]
|
|
31
10
|
const rowClassName = (row: ProductLine) => row.active ? '' : 'table-warning';
|
|
32
11
|
|
|
33
12
|
export default function TestTable() {
|
|
@@ -37,26 +16,25 @@ export default function TestTable() {
|
|
|
37
16
|
const [rowsPerPage, setRowsPerPage] = useState(5);
|
|
38
17
|
|
|
39
18
|
|
|
40
|
-
useEffect(() => {
|
|
41
|
-
setList([...productLines.sort(productLineSorter(sort))]);
|
|
42
|
-
setPage(0)
|
|
43
|
-
}, [sort]);
|
|
44
|
-
|
|
45
19
|
const rowsPerPageChangeHandler = (rpp: number) => {
|
|
46
20
|
setPage(0);
|
|
47
21
|
setRowsPerPage(rpp);
|
|
48
22
|
}
|
|
49
23
|
|
|
24
|
+
|
|
50
25
|
return (
|
|
51
26
|
<div>
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
27
|
+
<TableProvider initialFields={tableFields}>
|
|
28
|
+
<TableColumnsHandler/>
|
|
29
|
+
<SortableTableWithContext currentSort={sort} onChangeSort={setSort} size="lg" responsive
|
|
30
|
+
data={list.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)}
|
|
31
|
+
keyField="ProductLine" rowClassName={rowClassName}/>
|
|
32
|
+
</TableProvider>
|
|
55
33
|
<TablePagination page={page} onChangePage={setPage} size="sm"
|
|
56
34
|
rowsPerPage={rowsPerPage}
|
|
57
35
|
rowsPerPageProps={{
|
|
58
36
|
onChange: rowsPerPageChangeHandler,
|
|
59
|
-
label: <span className="bi-images"
|
|
37
|
+
label: <span className="bi-images"/>,
|
|
60
38
|
pageValues: [5, 10, 15, 25, 50, 100]
|
|
61
39
|
}}
|
|
62
40
|
showFirst={list.length > rowsPerPage}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {SortableTableField} from "../src";
|
|
2
|
+
import {ProductLine} from "./data";
|
|
3
|
+
import React from "react";
|
|
4
|
+
|
|
5
|
+
export const tableFields: SortableTableField<ProductLine>[] = [
|
|
6
|
+
{
|
|
7
|
+
id: 'prodLine',
|
|
8
|
+
field: 'ProductLine',
|
|
9
|
+
title: 'Prod Line',
|
|
10
|
+
sortable: true,
|
|
11
|
+
as: 'th'
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
id: 'ProductLineDesc',
|
|
15
|
+
field: 'ProductLineDesc',
|
|
16
|
+
title: 'Description',
|
|
17
|
+
sortable: true,
|
|
18
|
+
collapse: true,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: 'prodType',
|
|
22
|
+
field: 'ProductType',
|
|
23
|
+
title: 'Description',
|
|
24
|
+
sortable: true,
|
|
25
|
+
render: (row) => <span className="badge bg-info">{row.ProductType}</span>,
|
|
26
|
+
align: 'center'
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: 'valuation',
|
|
30
|
+
field: 'Valuation',
|
|
31
|
+
title: 'Valuation',
|
|
32
|
+
sortable: true,
|
|
33
|
+
render: (row) => <span className="badge bg-secondary">{row.Valuation}</span>,
|
|
34
|
+
align: 'center'
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: 'explodeKit',
|
|
38
|
+
field: 'ExplodeKitItems',
|
|
39
|
+
title: 'Explode Kit Items?',
|
|
40
|
+
sortable: true,
|
|
41
|
+
render: (row) => <span className="badge bg-primary">{row.ExplodeKitItems}</span>,
|
|
42
|
+
align: 'end'
|
|
43
|
+
},
|
|
44
|
+
]
|
package/vite.config.ts
CHANGED
|
@@ -16,13 +16,12 @@ export default defineConfig({
|
|
|
16
16
|
formats: ['es', 'cjs'],
|
|
17
17
|
},
|
|
18
18
|
rollupOptions: {
|
|
19
|
-
external: ['react', 'react/jsx-runtime', 'react-dom', '
|
|
19
|
+
external: ['react', 'react/jsx-runtime', 'react-dom', '@emotion/styled'],
|
|
20
20
|
output: {
|
|
21
21
|
globals:{
|
|
22
22
|
react: 'React',
|
|
23
23
|
'react-dom': 'ReactDOM',
|
|
24
24
|
'react/jsx-runtime': 'jsxRuntime',
|
|
25
|
-
classnames: 'classNames',
|
|
26
25
|
'@emotion/styled': 'styled'
|
|
27
26
|
}
|
|
28
27
|
}
|