schummar-table 0.2.1 → 0.4.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/dist/cjs/components/cell.d.ts +3 -2
- package/dist/cjs/components/cell.js +16 -13
- package/dist/cjs/components/columnSelection.js +1 -1
- package/dist/cjs/components/expandComponent.js +1 -1
- package/dist/cjs/components/export.js +1 -1
- package/dist/cjs/components/row.d.ts +3 -2
- package/dist/cjs/components/row.js +8 -5
- package/dist/cjs/components/textFilterComponent.d.ts +0 -1
- package/dist/cjs/components/textFilterComponent.js +0 -1
- package/dist/cjs/components/useCommonClasses.d.ts +1 -1
- package/dist/cjs/components/useCommonClasses.js +10 -6
- package/dist/cjs/components/virtualized.d.ts +1 -1
- package/dist/cjs/components/virtualized.js +5 -5
- package/dist/cjs/index.d.ts +2 -1
- package/dist/cjs/internalState/calcProps.js +23 -6
- package/dist/cjs/internalState/tableStateStorage.d.ts +11 -0
- package/dist/cjs/internalState/tableStateStorage.js +74 -0
- package/dist/cjs/misc/queue.d.ts +6 -0
- package/dist/cjs/misc/queue.js +42 -0
- package/dist/cjs/table.d.ts +3 -0
- package/dist/cjs/table.js +13 -2
- package/dist/cjs/types.d.ts +23 -6
- package/dist/esm/components/cell.d.ts +3 -2
- package/dist/esm/components/cell.js +16 -13
- package/dist/esm/components/columnSelection.js +1 -1
- package/dist/esm/components/expandComponent.js +1 -1
- package/dist/esm/components/export.js +2 -2
- package/dist/esm/components/row.d.ts +3 -2
- package/dist/esm/components/row.js +8 -5
- package/dist/esm/components/textFilterComponent.d.ts +0 -1
- package/dist/esm/components/textFilterComponent.js +0 -1
- package/dist/esm/components/useCommonClasses.d.ts +1 -1
- package/dist/esm/components/useCommonClasses.js +10 -6
- package/dist/esm/components/virtualized.d.ts +1 -1
- package/dist/esm/components/virtualized.js +5 -5
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/internalState/calcProps.js +24 -7
- package/dist/esm/internalState/tableStateStorage.d.ts +11 -0
- package/dist/esm/internalState/tableStateStorage.js +70 -0
- package/dist/esm/misc/queue.d.ts +6 -0
- package/dist/esm/misc/queue.js +38 -0
- package/dist/esm/table.d.ts +3 -0
- package/dist/esm/table.js +11 -1
- package/dist/esm/types.d.ts +23 -6
- package/package.json +11 -10
|
@@ -4,22 +4,25 @@ import { useColumnContext, useTableContext } from '..';
|
|
|
4
4
|
import { c } from '../misc/helpers';
|
|
5
5
|
import { calcClassName } from './row';
|
|
6
6
|
import { useCommonClasses } from './useCommonClasses';
|
|
7
|
-
export const Cell = memo(function Cell({ itemId }) {
|
|
7
|
+
export const Cell = memo(function Cell({ itemId, rowIndex }) {
|
|
8
8
|
var _a, _b;
|
|
9
9
|
const commonClasses = useCommonClasses();
|
|
10
10
|
const state = useTableContext();
|
|
11
11
|
const columnId = useColumnContext();
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const index = item ? state.activeItems.indexOf(item) : -1;
|
|
19
|
-
const className = c(calcClassName(state.props.classes, index), calcClassName(column === null || column === void 0 ? void 0 : column.classes, index));
|
|
20
|
-
const wrapCell = (_a = state.props.wrapCell) !== null && _a !== void 0 ? _a : ((cell) => _jsx("div", Object.assign({ className: c(commonClasses.cell, className) }, { children: cell }), void 0));
|
|
21
|
-
return wrapCell(column.renderCell(column.value(item), item), item);
|
|
22
|
-
}, [itemId, columnId, commonClasses]);
|
|
12
|
+
const column = state.useState((state) => state.activeColumns.find((column) => column.id === columnId), [columnId]);
|
|
13
|
+
const item = state.useState((state) => state.activeItemsById.get(itemId), [itemId]);
|
|
14
|
+
const classes = state.useState('props.classes');
|
|
15
|
+
let wrapCell = state.useState('props.wrapCell');
|
|
16
|
+
if (!column || !item)
|
|
17
|
+
return null;
|
|
23
18
|
(_b = (_a = state.getState().props).debug) === null || _b === void 0 ? void 0 : _b.call(_a, 'render cell', itemId, columnId);
|
|
24
|
-
|
|
19
|
+
const className = c(calcClassName(classes, item, rowIndex), calcClassName(column === null || column === void 0 ? void 0 : column.classes, item, rowIndex));
|
|
20
|
+
const content = column.renderCell(column.value(item), item);
|
|
21
|
+
if (!wrapCell && typeof content === 'string') {
|
|
22
|
+
wrapCell = (content) => (_jsx("div", Object.assign({ className: c(commonClasses.cell, className) }, { children: _jsx("span", Object.assign({ className: c(commonClasses.text) }, { children: content }), void 0) }), void 0));
|
|
23
|
+
}
|
|
24
|
+
else if (!wrapCell) {
|
|
25
|
+
wrapCell = (content) => _jsx("div", Object.assign({ className: c(commonClasses.cell, className) }, { children: content }), void 0);
|
|
26
|
+
}
|
|
27
|
+
return _jsx(_Fragment, { children: wrapCell(content, item) }, void 0);
|
|
25
28
|
});
|
|
@@ -29,5 +29,5 @@ export function ColumnSelection() {
|
|
|
29
29
|
}
|
|
30
30
|
onHiddenColumnsChange === null || onHiddenColumnsChange === void 0 ? void 0 : onHiddenColumnsChange(newValue);
|
|
31
31
|
};
|
|
32
|
-
return (_jsxs(_Fragment, { children: [_jsx(IconButton, Object.assign({ color: "inherit", onClick: (e) => setAnchor(e.currentTarget) }, { children: _jsx(Settings, {}, void 0) }), void 0), _jsx(Popover, Object.assign({ open: !!anchor, onClose: () => setAnchor(null), anchorEl: anchor, anchorOrigin: { vertical: 'bottom', horizontal: 'center' }, transformOrigin: { vertical: 'top', horizontal: '
|
|
32
|
+
return (_jsxs(_Fragment, { children: [_jsx(IconButton, Object.assign({ color: "inherit", size: "small", onClick: (e) => setAnchor(e.currentTarget) }, { children: _jsx(Settings, {}, void 0) }), void 0), _jsx(Popover, Object.assign({ open: !!anchor, onClose: () => setAnchor(null), anchorEl: anchor, anchorOrigin: { vertical: 'bottom', horizontal: 'center' }, transformOrigin: { vertical: 'top', horizontal: 'left' } }, { children: _jsx("div", Object.assign({ className: classes.list }, { children: columns.map((column) => (_jsx(FormControlLabel, { control: _jsx(Checkbox, { checked: !hiddenColumns.has(column.id), onChange: () => toggle(column), disabled: column.cannotHide }, void 0), label: column.header }, column.id))) }), void 0) }), void 0)] }, void 0));
|
|
33
33
|
}
|
|
@@ -27,7 +27,7 @@ export function ExpandComponent({ itemId }) {
|
|
|
27
27
|
});
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
return (_jsx(IconButton, Object.assign({ onClick: toggle }, { children: _jsx(ChevronRight, { style: {
|
|
30
|
+
return (_jsx(IconButton, Object.assign({ size: "small", onClick: toggle }, { children: _jsx(ChevronRight, { style: {
|
|
31
31
|
transition: 'all 500ms',
|
|
32
32
|
transform: isExpanded ? 'rotate3d(0, 0, 1, 90deg)' : 'none',
|
|
33
33
|
} }, void 0) }), void 0));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { Button, IconButton, makeStyles, Popover, Typography } from '@material-ui/core';
|
|
3
|
-
import { AssignmentReturn, CloudDownload
|
|
3
|
+
import { AssignmentReturn, CloudDownload } from '@material-ui/icons';
|
|
4
4
|
import { useState } from 'react';
|
|
5
5
|
import { csvExport } from '../misc/csvExport';
|
|
6
6
|
import { useTableContext } from '../table';
|
|
@@ -40,5 +40,5 @@ export function Export() {
|
|
|
40
40
|
a.click();
|
|
41
41
|
document.body.removeChild(a);
|
|
42
42
|
};
|
|
43
|
-
return (_jsxs(_Fragment, { children: [_jsx(IconButton, Object.assign({ color: "inherit", onClick: (e) => setAnchor(e.currentTarget) }, { children: _jsx(
|
|
43
|
+
return (_jsxs(_Fragment, { children: [_jsx(IconButton, Object.assign({ color: "inherit", size: "small", onClick: (e) => setAnchor(e.currentTarget) }, { children: _jsx(CloudDownload, {}, void 0) }), void 0), _jsx(Popover, Object.assign({ open: !!anchor, onClose: () => setAnchor(null), anchorEl: anchor, anchorOrigin: { vertical: 'bottom', horizontal: 'center' }, transformOrigin: { vertical: 'top', horizontal: 'left' } }, { children: _jsxs("div", Object.assign({ className: classes.dialog }, { children: [_jsx(Typography, Object.assign({ variant: "caption" }, { children: textTitle !== null && textTitle !== void 0 ? textTitle : 'Export' }), void 0), _jsx(Button, Object.assign({ startIcon: _jsx(AssignmentReturn, {}, void 0), fullWidth: true, onClick: copy }, { children: textCopy !== null && textCopy !== void 0 ? textCopy : 'In die Zwischenablage' }), void 0), _jsx(Button, Object.assign({ startIcon: _jsx(CloudDownload, {}, void 0), fullWidth: true, onClick: download }, { children: textDownload !== null && textDownload !== void 0 ? textDownload : 'Herunterladen' }), void 0)] }), void 0) }), void 0)] }, void 0));
|
|
44
44
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Id, InternalColumn } from '../types';
|
|
3
|
-
export declare
|
|
4
|
-
export declare const Row: React.MemoExoticComponent<(<T>({ itemId }: {
|
|
3
|
+
export declare function calcClassName<T>(classes: InternalColumn<any, any>['classes'] | undefined, item: T, index: number): string;
|
|
4
|
+
export declare const Row: React.MemoExoticComponent<(<T>({ itemId, rowIndex }: {
|
|
5
5
|
itemId: Id;
|
|
6
|
+
rowIndex: number;
|
|
6
7
|
}) => JSX.Element | null)>;
|
|
@@ -6,23 +6,26 @@ import { Cell } from './cell';
|
|
|
6
6
|
import { ExpandComponent } from './expandComponent';
|
|
7
7
|
import { SelectComponent } from './selectComponent';
|
|
8
8
|
import { useCommonClasses } from './useCommonClasses';
|
|
9
|
-
export
|
|
10
|
-
|
|
9
|
+
export function calcClassName(classes, item, index) {
|
|
10
|
+
return c((classes === null || classes === void 0 ? void 0 : classes.cell) instanceof Function ? classes.cell(item, index) : classes === null || classes === void 0 ? void 0 : classes.cell, (classes === null || classes === void 0 ? void 0 : classes.evenCell) === undefined ? undefined : { [classes.evenCell]: index % 2 === 0 }, (classes === null || classes === void 0 ? void 0 : classes.oddCell) === undefined ? undefined : { [classes.oddCell]: index % 2 === 1 });
|
|
11
|
+
}
|
|
12
|
+
export const Row = memo(function Row({ itemId, rowIndex }) {
|
|
11
13
|
var _a, _b;
|
|
12
14
|
const commonClasses = useCommonClasses();
|
|
13
15
|
const state = useTableContext();
|
|
14
16
|
const divRef = useRef(null);
|
|
15
|
-
const { className, indent, hasChildren, hasDeferredChildren, columnIds, enableSelection } = state.useState((state) => {
|
|
17
|
+
const { className, indent, hasChildren, hasDeferredChildren, columnIds, enableSelection, rowAction } = state.useState((state) => {
|
|
16
18
|
var _a, _b;
|
|
17
19
|
const item = state.activeItemsById.get(itemId);
|
|
18
20
|
const index = !item ? -1 : state.activeItems.indexOf(item);
|
|
19
21
|
return {
|
|
20
|
-
className: calcClassName(state.props.classes, index),
|
|
22
|
+
className: calcClassName(state.props.classes, item, index),
|
|
21
23
|
indent: item ? getAncestors(state.activeItemsById, item).size : 0,
|
|
22
24
|
hasChildren: !!(item === null || item === void 0 ? void 0 : item.children.length),
|
|
23
25
|
hasDeferredChildren: item && ((_b = (_a = state.props).hasDeferredChildren) === null || _b === void 0 ? void 0 : _b.call(_a, item)),
|
|
24
26
|
columnIds: state.activeColumns.map((column) => column.id),
|
|
25
27
|
enableSelection: state.props.enableSelection,
|
|
28
|
+
rowAction: state.props.rowAction instanceof Function ? (item ? state.props.rowAction(item, index) : null) : state.props.rowAction,
|
|
26
29
|
};
|
|
27
30
|
}, [itemId]);
|
|
28
31
|
useEffect(() => {
|
|
@@ -40,5 +43,5 @@ export const Row = memo(function Row({ itemId }) {
|
|
|
40
43
|
return () => o.disconnect();
|
|
41
44
|
}, [divRef.current]);
|
|
42
45
|
(_b = (_a = state.getState().props).debug) === null || _b === void 0 ? void 0 : _b.call(_a, 'render row', itemId);
|
|
43
|
-
return (_jsxs(_Fragment, { children: [_jsx("div", { className: c(commonClasses.cellFill, className), ref: divRef }, void 0), _jsxs("div", Object.assign({ className: c(commonClasses.cell, commonClasses.firstCell, className) }, { children: [_jsx("div", { style: { width: indent * 20 } }, void 0), enableSelection && _jsx(SelectComponent, { itemId: itemId }, void 0), (hasChildren || hasDeferredChildren) && _jsx(ExpandComponent, { itemId: itemId }, void 0)] }), void 0), columnIds.map((columnId) => (_jsx(ColumnContext.Provider, Object.assign({ value: columnId }, { children: _jsx(Cell, { itemId: itemId }, void 0) }), columnId))), _jsx("div", { className: c(commonClasses.cellFill, className) }, void 0)] }, void 0));
|
|
46
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { className: c(commonClasses.cellFill, className), ref: divRef }, void 0), _jsxs("div", Object.assign({ className: c(commonClasses.cell, commonClasses.firstCell, className) }, { children: [_jsx("div", { style: { width: indent * 20 } }, void 0), enableSelection && _jsx(SelectComponent, { itemId: itemId }, void 0), (hasChildren || hasDeferredChildren) && _jsx(ExpandComponent, { itemId: itemId }, void 0), rowAction] }), void 0), columnIds.map((columnId) => (_jsx(ColumnContext.Provider, Object.assign({ value: columnId }, { children: _jsx(Cell, { itemId: itemId, rowIndex: rowIndex }, void 0) }), columnId))), _jsx("div", { className: c(commonClasses.cellFill, className) }, void 0)] }, void 0));
|
|
44
47
|
});
|
|
@@ -3,7 +3,6 @@ import { IconButton, makeStyles, TextField } from '@material-ui/core';
|
|
|
3
3
|
import { Clear, Search } from '@material-ui/icons';
|
|
4
4
|
import { useEffect, useState } from 'react';
|
|
5
5
|
import { asString } from '../misc/helpers';
|
|
6
|
-
import '../misc/textMatch';
|
|
7
6
|
import { textMatch } from '../misc/textMatch';
|
|
8
7
|
import { useColumnContext, useTableContext } from '../table';
|
|
9
8
|
export class TextFilter {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const useCommonClasses: (props?: any) => import("@material-ui/styles").ClassNameMap<"table" | "cell" | "sticky" | "headerCell" | "cellFill" | "firstCell" | "headerFill" | "deferredPlaceholder">;
|
|
1
|
+
export declare const useCommonClasses: (props?: any) => import("@material-ui/styles").ClassNameMap<"table" | "text" | "cell" | "sticky" | "headerCell" | "cellFill" | "firstCell" | "headerFill" | "deferredPlaceholder">;
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { makeStyles } from '@material-ui/core';
|
|
2
2
|
const cell = (theme) => ({
|
|
3
|
-
padding: theme.spacing(0.
|
|
4
|
-
display: '
|
|
5
|
-
gridAutoFlow: 'column',
|
|
3
|
+
padding: theme.spacing(0.1, 1),
|
|
4
|
+
display: 'flex',
|
|
6
5
|
alignItems: 'center',
|
|
7
6
|
borderBottom: `1px solid ${theme.palette.grey[200]}`,
|
|
8
7
|
whiteSpace: 'nowrap',
|
|
9
8
|
overflow: 'hidden',
|
|
10
|
-
textOverflow: 'ellipsis',
|
|
11
9
|
});
|
|
12
10
|
export const useCommonClasses = makeStyles((theme) => ({
|
|
13
11
|
table: {
|
|
@@ -18,7 +16,7 @@ export const useCommonClasses = makeStyles((theme) => ({
|
|
|
18
16
|
cellFill: {
|
|
19
17
|
borderBottom: `1px solid ${theme.palette.grey[200]}`,
|
|
20
18
|
},
|
|
21
|
-
headerCell: Object.assign(Object.assign({}, cell(theme)), { borderBottom:
|
|
19
|
+
headerCell: Object.assign(Object.assign({}, cell(theme)), { borderBottom: `2px solid ${theme.palette.grey[400]}`, gridTemplateColumns: 'minmax(0, 1fr) max-content', background: theme.palette.common.white, '&:not(:first-child)': {
|
|
22
20
|
borderLeft: `1px solid ${theme.palette.background.default}`,
|
|
23
21
|
} }),
|
|
24
22
|
firstCell: {
|
|
@@ -30,7 +28,8 @@ export const useCommonClasses = makeStyles((theme) => ({
|
|
|
30
28
|
zIndex: 1,
|
|
31
29
|
},
|
|
32
30
|
headerFill: {
|
|
33
|
-
|
|
31
|
+
borderBottom: `3px solid ${theme.palette.grey[200]}`,
|
|
32
|
+
background: theme.palette.common.white,
|
|
34
33
|
},
|
|
35
34
|
deferredPlaceholder: {
|
|
36
35
|
padding: theme.spacing(1),
|
|
@@ -39,4 +38,9 @@ export const useCommonClasses = makeStyles((theme) => ({
|
|
|
39
38
|
display: 'grid',
|
|
40
39
|
justifyContent: 'center',
|
|
41
40
|
},
|
|
41
|
+
text: {
|
|
42
|
+
minWidth: 0,
|
|
43
|
+
overflow: 'hidden',
|
|
44
|
+
textOverflow: 'ellipsis',
|
|
45
|
+
},
|
|
42
46
|
}));
|
|
@@ -2,5 +2,5 @@ import { HTMLProps, ReactNode } from 'react';
|
|
|
2
2
|
import { Id } from '../types';
|
|
3
3
|
export declare function Virtualized<T>({ header, children, ...props }: {
|
|
4
4
|
header: ReactNode;
|
|
5
|
-
children: (itemIds: Id[]) => ReactNode;
|
|
5
|
+
children: (itemIds: Id[], startIndex: number) => ReactNode;
|
|
6
6
|
} & HTMLProps<HTMLDivElement>): JSX.Element;
|
|
@@ -47,7 +47,7 @@ export function Virtualized(_a) {
|
|
|
47
47
|
const virtual = state.useState('props.virtual');
|
|
48
48
|
const probeRef = useRef(null);
|
|
49
49
|
const [counter, setCounter] = useState(0);
|
|
50
|
-
const { itemIds = [], from, to, before = 0, after = 0, } = state.useState((state) => {
|
|
50
|
+
const { itemIds = [], from = 0, to, before = 0, after = 0, } = state.useState((state) => {
|
|
51
51
|
var _a;
|
|
52
52
|
const itemIds = state.activeItems.map((item) => item.id);
|
|
53
53
|
const root = probeRef.current && findScrollRoot(probeRef.current);
|
|
@@ -55,7 +55,7 @@ export function Virtualized(_a) {
|
|
|
55
55
|
return { itemIds };
|
|
56
56
|
if (!probeRef.current || !root || !document.contains(root))
|
|
57
57
|
return {};
|
|
58
|
-
const { rowHeight, initalRowHeight } = (_a = (state.props.virtual instanceof Object ? state.props.virtual : undefined)) !== null && _a !== void 0 ? _a : {};
|
|
58
|
+
const { rowHeight, initalRowHeight, overscan = 200, overscanTop, overscanBottom, } = (_a = (state.props.virtual instanceof Object ? state.props.virtual : undefined)) !== null && _a !== void 0 ? _a : {};
|
|
59
59
|
let totalHeight = 0;
|
|
60
60
|
const rowHeights = itemIds.map((itemId, index) => {
|
|
61
61
|
var _a, _b;
|
|
@@ -69,13 +69,13 @@ export function Virtualized(_a) {
|
|
|
69
69
|
const bottomOfTable = topOfTable + root.clientHeight - headerHeight;
|
|
70
70
|
let from = 0, to = itemIds.length, before = 0, after = 0;
|
|
71
71
|
for (const h of rowHeights) {
|
|
72
|
-
if (before + h > topOfTable)
|
|
72
|
+
if (before + h > topOfTable - (overscanTop !== null && overscanTop !== void 0 ? overscanTop : overscan))
|
|
73
73
|
break;
|
|
74
74
|
from++;
|
|
75
75
|
before += h;
|
|
76
76
|
}
|
|
77
77
|
for (const h of rowHeights.reverse()) {
|
|
78
|
-
if (after + h > totalHeight - bottomOfTable)
|
|
78
|
+
if (after + h > totalHeight - bottomOfTable - (overscanBottom !== null && overscanBottom !== void 0 ? overscanBottom : overscan))
|
|
79
79
|
break;
|
|
80
80
|
to--;
|
|
81
81
|
after += h;
|
|
@@ -90,5 +90,5 @@ export function Virtualized(_a) {
|
|
|
90
90
|
return onAncestorScroll(probeRef.current, incCounter);
|
|
91
91
|
}, [probeRef.current, incCounter]);
|
|
92
92
|
(_e = (_d = state.getState().props).debug) === null || _e === void 0 ? void 0 : _e.call(_d, `Virtualalized render ${from} to ${to}`);
|
|
93
|
-
return (_jsxs("div", Object.assign({}, props, { children: [header, virtual && _jsx("div", { style: { gridColumn: '1 / -1', height: before }, ref: probeRef }, void 0), children(itemIds), virtual && _jsx("div", { style: { gridColumn: '1 / -1', height: after } }, void 0)] }), void 0));
|
|
93
|
+
return (_jsxs("div", Object.assign({}, props, { children: [header, virtual && _jsx("div", { style: { gridColumn: '1 / -1', height: before }, ref: probeRef }, void 0), children(itemIds, from), virtual && _jsx("div", { style: { gridColumn: '1 / -1', height: after } }, void 0)] }), void 0));
|
|
94
94
|
}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { DefaultFilter, DefaultFilterComponent } from './components/defaultFilterComponent';
|
|
2
|
+
export type { Filter } from './components/filterComponent';
|
|
2
3
|
export { TextFilter, TextFilterComponent } from './components/textFilterComponent';
|
|
3
4
|
export { termMatch, textMatch } from './misc/textMatch';
|
|
4
5
|
export { ColumnContext, Table, TableContext, useColumnContext, useTableContext } from './table';
|
|
5
|
-
export type { Column, Id, Rows, Sort, SortDirection, TableProps } from './types';
|
|
6
|
+
export type { Column, Id, InternalColumn, Rows, Sort, SortDirection, TableProps } from './types';
|
|
@@ -9,10 +9,11 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
9
9
|
}
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
|
-
import { useMemo } from 'react';
|
|
12
|
+
import { useMemo, useRef } from 'react';
|
|
13
13
|
import { asString } from '../misc/helpers';
|
|
14
14
|
const noopParentId = () => undefined;
|
|
15
15
|
export function calcProps(props) {
|
|
16
|
+
const columnCache = useRef(new Map());
|
|
16
17
|
return useMemo(() => {
|
|
17
18
|
var _a, _b;
|
|
18
19
|
let id;
|
|
@@ -37,15 +38,31 @@ export function calcProps(props) {
|
|
|
37
38
|
inputColumns = props.columns((value, column) => (Object.assign(Object.assign({}, column), { value })));
|
|
38
39
|
}
|
|
39
40
|
else {
|
|
40
|
-
inputColumns = props.columns;
|
|
41
|
+
inputColumns = props.columns.map((column) => (Object.assign(Object.assign({}, column), { dependecies: undefined })));
|
|
41
42
|
}
|
|
43
|
+
const newColumnCache = new Map();
|
|
42
44
|
const columns = inputColumns.map(function (_a, index) {
|
|
43
|
-
var
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
var _b;
|
|
46
|
+
var { id, header = null, renderCell = asString, exportCell = asString, sortBy = (v) => (typeof v === 'number' || v instanceof Date ? v : String(v)), dependencies = [] } = _a, props = __rest(_a, ["id", "header", "renderCell", "exportCell", "sortBy", "dependencies"]);
|
|
47
|
+
const [depsInCache, columnInCache] = (_b = columnCache.current.get(id !== null && id !== void 0 ? id : index)) !== null && _b !== void 0 ? _b : [];
|
|
48
|
+
let column;
|
|
49
|
+
if (depsInCache &&
|
|
50
|
+
columnInCache &&
|
|
51
|
+
depsInCache.length === dependencies.length &&
|
|
52
|
+
depsInCache.every((x, i) => dependencies[i] === x)) {
|
|
53
|
+
column = columnInCache;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
column = Object.assign({ id: id !== null && id !== void 0 ? id : index, header,
|
|
57
|
+
renderCell,
|
|
58
|
+
exportCell,
|
|
59
|
+
sortBy,
|
|
60
|
+
dependencies }, props);
|
|
61
|
+
}
|
|
62
|
+
newColumnCache.set(id !== null && id !== void 0 ? id : index, [dependencies, column]);
|
|
63
|
+
return column;
|
|
48
64
|
});
|
|
65
|
+
columnCache.current = newColumnCache;
|
|
49
66
|
let copy;
|
|
50
67
|
if (props.enableExport === true || (props.enableExport instanceof Object && props.enableExport.copy === true)) {
|
|
51
68
|
copy = { separator: '\t' };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare type TableStateStorage = {
|
|
2
|
+
getItem: (key: string) => string | null | Promise<string | null>;
|
|
3
|
+
setItem: (key: string, value: string) => unknown | Promise<unknown>;
|
|
4
|
+
removeItem: (key: string) => unknown | Promise<unknown>;
|
|
5
|
+
} & ({
|
|
6
|
+
keys: () => string[] | Promise<string[]>;
|
|
7
|
+
} | {
|
|
8
|
+
length: number | (() => number | Promise<number>);
|
|
9
|
+
key: (keyIndex: number) => string | null | Promise<string | null>;
|
|
10
|
+
});
|
|
11
|
+
export declare function useTableStateStorage(): void;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { useEffect } from 'react';
|
|
11
|
+
import { useTableContext } from '..';
|
|
12
|
+
import { Queue } from '../misc/queue';
|
|
13
|
+
const KEYS = ['sort', 'selection', 'expanded', 'hiddenColumns'];
|
|
14
|
+
export function useTableStateStorage() {
|
|
15
|
+
const state = useTableContext();
|
|
16
|
+
// On mount: load
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
const { storeState, debug } = state.getState().props;
|
|
19
|
+
if (!storeState)
|
|
20
|
+
return;
|
|
21
|
+
let isCanceled = false;
|
|
22
|
+
const q = new Queue();
|
|
23
|
+
q.run(() => __awaiter(this, void 0, void 0, function* () {
|
|
24
|
+
try {
|
|
25
|
+
const { storage, id = 'table', include } = storeState;
|
|
26
|
+
const json = yield storage.getItem(`${id}_state`);
|
|
27
|
+
if (isCanceled || !json)
|
|
28
|
+
return;
|
|
29
|
+
const data = JSON.parse(json);
|
|
30
|
+
state.update((state) => {
|
|
31
|
+
for (const key of KEYS) {
|
|
32
|
+
if (!include || include[key]) {
|
|
33
|
+
const value = key === 'sort' ? data.sort : new Set(data[key]);
|
|
34
|
+
state[key] = value;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
catch (e) {
|
|
40
|
+
debug === null || debug === void 0 ? void 0 : debug('Failed to load table state:', e);
|
|
41
|
+
}
|
|
42
|
+
}));
|
|
43
|
+
state.subscribe((state) => {
|
|
44
|
+
if (!state.props.storeState)
|
|
45
|
+
return;
|
|
46
|
+
const data = {};
|
|
47
|
+
for (const key of KEYS) {
|
|
48
|
+
if (!state.props.storeState.include || state.props.storeState.include[key]) {
|
|
49
|
+
const value = key === 'sort' ? state.sort : Array.from(state[key]);
|
|
50
|
+
data[key] = value;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
storage: state.props.storeState.storage,
|
|
55
|
+
id: state.props.storeState.id,
|
|
56
|
+
data,
|
|
57
|
+
};
|
|
58
|
+
}, (props) => {
|
|
59
|
+
if (!props)
|
|
60
|
+
return;
|
|
61
|
+
const { storage, id = 'table', data } = props;
|
|
62
|
+
q.run(() => __awaiter(this, void 0, void 0, function* () {
|
|
63
|
+
yield storage.setItem(`${id}_state`, JSON.stringify(data));
|
|
64
|
+
}));
|
|
65
|
+
});
|
|
66
|
+
return () => {
|
|
67
|
+
isCanceled = true;
|
|
68
|
+
};
|
|
69
|
+
}, []);
|
|
70
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
export class Queue {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.q = new Array();
|
|
13
|
+
this.isRunning = false;
|
|
14
|
+
}
|
|
15
|
+
run(job) {
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
this.q.push({ job, resolve, reject });
|
|
18
|
+
if (!this.isRunning)
|
|
19
|
+
this.start();
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
start() {
|
|
23
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
24
|
+
this.isRunning = true;
|
|
25
|
+
let next;
|
|
26
|
+
while ((next = this.q.shift())) {
|
|
27
|
+
try {
|
|
28
|
+
const result = yield next.job();
|
|
29
|
+
next.resolve(result);
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
next.reject(e);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
this.isRunning = false;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
package/dist/esm/table.d.ts
CHANGED
|
@@ -5,4 +5,7 @@ export declare const TableContext: React.Context<Store<InternalTableState<any>>
|
|
|
5
5
|
export declare const ColumnContext: React.Context<Id | null>;
|
|
6
6
|
export declare function useTableContext<T>(): Store<InternalTableState<T>>;
|
|
7
7
|
export declare function useColumnContext(): Id;
|
|
8
|
+
declare let defaultProps: Pick<TableProps<unknown>, 'text' | 'classes'>;
|
|
9
|
+
export declare function configureTables(props: typeof defaultProps): void;
|
|
8
10
|
export declare function Table<T>(props: TableProps<T>): JSX.Element;
|
|
11
|
+
export {};
|
package/dist/esm/table.js
CHANGED
|
@@ -8,6 +8,7 @@ import { SelectComponent } from './components/selectComponent';
|
|
|
8
8
|
import { SortComponent } from './components/sortComponent';
|
|
9
9
|
import { useCommonClasses } from './components/useCommonClasses';
|
|
10
10
|
import { Virtualized } from './components/virtualized';
|
|
11
|
+
import { useTableStateStorage } from './internalState/tableStateStorage';
|
|
11
12
|
import { useTableState } from './internalState/useTableState';
|
|
12
13
|
import { c } from './misc/helpers';
|
|
13
14
|
export const TableContext = createContext(null);
|
|
@@ -24,14 +25,23 @@ export function useColumnContext() {
|
|
|
24
25
|
throw Error('No column context available');
|
|
25
26
|
return value;
|
|
26
27
|
}
|
|
28
|
+
let defaultProps = {};
|
|
29
|
+
export function configureTables(props) {
|
|
30
|
+
defaultProps = props;
|
|
31
|
+
}
|
|
32
|
+
function mergeProps(props) {
|
|
33
|
+
return Object.assign(Object.assign({}, props), { text: Object.assign(Object.assign({}, defaultProps.text), props.text), classes: Object.assign(Object.assign({}, defaultProps.classes), props.classes) });
|
|
34
|
+
}
|
|
27
35
|
export function Table(props) {
|
|
28
36
|
var _a, _b;
|
|
37
|
+
props = mergeProps(props);
|
|
29
38
|
const state = useTableState(props);
|
|
30
39
|
(_b = (_a = state.getState().props).debug) === null || _b === void 0 ? void 0 : _b.call(_a, 'render table');
|
|
31
40
|
return (_jsx(TableContext.Provider, Object.assign({ value: state }, { children: _jsx(TableInner, {}, void 0) }), void 0));
|
|
32
41
|
}
|
|
33
42
|
const TableInner = memo(function TableInner() {
|
|
34
43
|
var _a, _b;
|
|
44
|
+
useTableStateStorage();
|
|
35
45
|
const commonClasses = useCommonClasses();
|
|
36
46
|
const state = useTableContext();
|
|
37
47
|
const fullWidth = state.useState('props.fullWidth');
|
|
@@ -59,5 +69,5 @@ const TableInner = memo(function TableInner() {
|
|
|
59
69
|
}, header: _jsxs(_Fragment, { children: [_jsx("div", { className: c(commonClasses.headerFill, { [commonClasses.sticky]: !!stickyHeader }, classes === null || classes === void 0 ? void 0 : classes.headerCell) }, void 0), _jsxs("div", Object.assign({ className: c(commonClasses.headerCell, { [commonClasses.sticky]: !!stickyHeader }, classes === null || classes === void 0 ? void 0 : classes.headerCell) }, { children: [enableSelection && _jsx(SelectComponent, {}, void 0), enableColumnSelection && _jsx(ColumnSelection, {}, void 0), enableExport && _jsx(Export, {}, void 0)] }), void 0), activeColumns.map((column) => {
|
|
60
70
|
var _a;
|
|
61
71
|
return (_jsx(ColumnContext.Provider, Object.assign({ value: column.id }, { children: _jsxs("div", Object.assign({ className: c(commonClasses.headerCell, { [commonClasses.sticky]: !!stickyHeader }, classes === null || classes === void 0 ? void 0 : classes.headerCell, (_a = column.classes) === null || _a === void 0 ? void 0 : _a.headerCell) }, { children: [_jsx(SortComponent, { children: column.header }, void 0), _jsx(FilterComponent, {}, void 0)] }), column.id) }), column.id));
|
|
62
|
-
}), _jsx("div", { className: c(commonClasses.headerFill, { [commonClasses.sticky]: !!stickyHeader }, classes === null || classes === void 0 ? void 0 : classes.headerCell) }, void 0)] }, void 0) }, { children: (itemIds) => itemIds.map((itemId) => _jsx(Row, { itemId: itemId }, itemId)) }), void 0));
|
|
72
|
+
}), _jsx("div", { className: c(commonClasses.headerFill, { [commonClasses.sticky]: !!stickyHeader }, classes === null || classes === void 0 ? void 0 : classes.headerCell) }, void 0)] }, void 0) }, { children: (itemIds, startIndex) => itemIds.map((itemId, index) => _jsx(Row, { itemId: itemId, rowIndex: startIndex + index }, itemId)) }), void 0));
|
|
63
73
|
});
|
package/dist/esm/types.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { CSSProperties, ReactNode } from 'react';
|
|
2
2
|
import { Filter } from './components/filterComponent';
|
|
3
3
|
import { CsvExportOptions } from './misc/csvExport';
|
|
4
|
+
import { TableStateStorage } from './internalState/tableStateStorage';
|
|
4
5
|
export declare type Sort = {
|
|
5
6
|
columnId: string | number;
|
|
6
7
|
direction: SortDirection;
|
|
@@ -16,6 +17,7 @@ export declare type TableProps<T> = {
|
|
|
16
17
|
parentId?: ((item: T) => Id | undefined) | KeyOfType<T, Id | undefined>;
|
|
17
18
|
hasDeferredChildren?: (item: T) => boolean;
|
|
18
19
|
columns: Column<T, any>[] | ((col: <V>(value: (item: T) => V, column: Omit<Column<T, V>, 'value'>) => Column<T, V>) => Column<T, any>[]);
|
|
20
|
+
rowAction?: ReactNode | ((item: T, index: number) => ReactNode);
|
|
19
21
|
defaultSort?: Sort[];
|
|
20
22
|
sort?: Sort[];
|
|
21
23
|
onSortChange?: (sort: Sort[]) => void;
|
|
@@ -38,17 +40,20 @@ export declare type TableProps<T> = {
|
|
|
38
40
|
rowHeight?: number;
|
|
39
41
|
initalRowHeight?: number;
|
|
40
42
|
throttleScroll?: number;
|
|
43
|
+
overscan?: number;
|
|
44
|
+
overscanBottom?: number;
|
|
45
|
+
overscanTop?: number;
|
|
41
46
|
};
|
|
42
47
|
text?: {
|
|
43
|
-
deselectAll?:
|
|
44
|
-
exportTitle?:
|
|
45
|
-
exportCopy?:
|
|
46
|
-
exportDownload?:
|
|
48
|
+
deselectAll?: ReactNode;
|
|
49
|
+
exportTitle?: ReactNode;
|
|
50
|
+
exportCopy?: ReactNode;
|
|
51
|
+
exportDownload?: ReactNode;
|
|
47
52
|
};
|
|
48
53
|
classes?: {
|
|
49
54
|
table?: string;
|
|
50
55
|
headerCell?: string;
|
|
51
|
-
cell?: string;
|
|
56
|
+
cell?: string | ((item: T, index: number) => string | undefined);
|
|
52
57
|
evenCell?: string;
|
|
53
58
|
oddCell?: string;
|
|
54
59
|
};
|
|
@@ -60,6 +65,16 @@ export declare type TableProps<T> = {
|
|
|
60
65
|
copy?: boolean | CsvExportOptions;
|
|
61
66
|
download?: boolean | CsvExportOptions;
|
|
62
67
|
};
|
|
68
|
+
storeState?: {
|
|
69
|
+
storage: TableStateStorage;
|
|
70
|
+
id?: string;
|
|
71
|
+
include?: {
|
|
72
|
+
sort?: boolean;
|
|
73
|
+
selection?: boolean;
|
|
74
|
+
expanded?: boolean;
|
|
75
|
+
hiddenColumns?: boolean;
|
|
76
|
+
};
|
|
77
|
+
};
|
|
63
78
|
};
|
|
64
79
|
export declare type InternalTableProps<T> = Omit<TableProps<T>, 'id' | 'parentId' | 'columns' | 'enableSelection' | 'enableColumnSelection' | 'enableExport'> & {
|
|
65
80
|
id: (item: T) => Id;
|
|
@@ -93,10 +108,12 @@ export declare type Column<T, V> = {
|
|
|
93
108
|
justifyContent?: CSSProperties['justifyContent'];
|
|
94
109
|
classes?: {
|
|
95
110
|
headerCell?: string;
|
|
96
|
-
cell?: string;
|
|
111
|
+
cell?: string | ((item: T, index: number) => string | undefined);
|
|
97
112
|
evenCell?: string;
|
|
98
113
|
oddCell?: string;
|
|
99
114
|
};
|
|
115
|
+
/** If the column definition changes, supply parameters that it depends on. If not set, the column will not update */
|
|
116
|
+
dependencies?: any[];
|
|
100
117
|
};
|
|
101
118
|
export declare type InternalColumn<T, V> = Required<Omit<Column<T, V>, 'id'> & {
|
|
102
119
|
id: Id;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "schummar-table",
|
|
3
3
|
"repository": "schummar/schummar-table",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.0",
|
|
5
5
|
"description": "",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"sideEffects": false,
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"license": "ISC",
|
|
19
19
|
"scripts": {
|
|
20
20
|
"start": "npm --prefix example run dev",
|
|
21
|
-
"dev": "run-p
|
|
21
|
+
"dev": "run-p dev:*",
|
|
22
22
|
"dev:esm": "tsc --watch",
|
|
23
23
|
"dev:cjs": "tsc -p tsconfig-cjs.json --watch",
|
|
24
24
|
"build": "npm-run-all -s build:clean -p build:compile:*",
|
|
@@ -42,15 +42,16 @@
|
|
|
42
42
|
"schummar-state": ">=0.0.36"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@testing-library/react": "^12.1.
|
|
45
|
+
"@testing-library/react": "^12.1.2",
|
|
46
46
|
"@types/react": "*",
|
|
47
|
-
"@typescript-eslint/eslint-plugin": "^4.
|
|
48
|
-
"@typescript-eslint/parser": "^4.
|
|
47
|
+
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
|
48
|
+
"@typescript-eslint/parser": "^5.4.0",
|
|
49
49
|
"ava": "^3.15.0",
|
|
50
|
-
"eslint": "^
|
|
51
|
-
"global-jsdom": "^8.
|
|
50
|
+
"eslint": "^8.2.0",
|
|
51
|
+
"global-jsdom": "^8.3.0",
|
|
52
52
|
"immer": "*",
|
|
53
|
-
"jsdom": "^
|
|
53
|
+
"jsdom": "^18.1.0",
|
|
54
|
+
"localforage": "^1.10.0",
|
|
54
55
|
"npm-run-all": "^4.1.5",
|
|
55
56
|
"nyc": "^15.1.0",
|
|
56
57
|
"prettier": "^2.4.1",
|
|
@@ -58,8 +59,8 @@
|
|
|
58
59
|
"react-dom": "^17.0.2",
|
|
59
60
|
"rimraf": "^3.0.2",
|
|
60
61
|
"schummar-state": "*",
|
|
61
|
-
"ts-node": "^
|
|
62
|
-
"typescript": "^4.
|
|
62
|
+
"ts-node": "^10.4.0",
|
|
63
|
+
"typescript": "^4.5.2"
|
|
63
64
|
},
|
|
64
65
|
"files": [
|
|
65
66
|
"dist"
|