schummar-table 0.1.0 → 0.3.1

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.
Files changed (48) hide show
  1. package/dist/cjs/components/cell.d.ts +3 -2
  2. package/dist/cjs/components/cell.js +19 -14
  3. package/dist/cjs/components/columnSelection.js +4 -4
  4. package/dist/cjs/components/defaultFilterComponent.js +11 -12
  5. package/dist/cjs/components/expandComponent.js +3 -3
  6. package/dist/cjs/components/export.d.ts +2 -0
  7. package/dist/cjs/components/export.js +48 -0
  8. package/dist/cjs/components/filterComponent.js +5 -5
  9. package/dist/cjs/components/row.d.ts +2 -1
  10. package/dist/cjs/components/row.js +11 -10
  11. package/dist/cjs/components/selectComponent.js +5 -5
  12. package/dist/cjs/components/sortComponent.js +4 -4
  13. package/dist/cjs/components/textFilterComponent.js +7 -7
  14. package/dist/cjs/components/useCommonClasses.d.ts +1 -1
  15. package/dist/cjs/components/useCommonClasses.js +11 -7
  16. package/dist/cjs/components/virtualized.d.ts +1 -1
  17. package/dist/cjs/components/virtualized.js +10 -10
  18. package/dist/cjs/internalState/calcItems.js +7 -7
  19. package/dist/cjs/internalState/calcProps.js +50 -35
  20. package/dist/cjs/internalState/cleanupState.js +3 -3
  21. package/dist/cjs/internalState/filterColumns.js +1 -1
  22. package/dist/cjs/internalState/syncSelections.js +1 -1
  23. package/dist/cjs/internalState/useTableState.js +8 -8
  24. package/dist/cjs/misc/csvExport.d.ts +7 -0
  25. package/dist/cjs/misc/csvExport.js +15 -0
  26. package/dist/cjs/misc/helpers.js +1 -1
  27. package/dist/cjs/misc/textMatch.js +1 -1
  28. package/dist/cjs/table.js +16 -12
  29. package/dist/cjs/types.d.ts +26 -4
  30. package/dist/esm/components/cell.d.ts +3 -2
  31. package/dist/esm/components/cell.js +17 -12
  32. package/dist/esm/components/columnSelection.js +1 -1
  33. package/dist/esm/components/defaultFilterComponent.js +1 -2
  34. package/dist/esm/components/expandComponent.js +1 -1
  35. package/dist/esm/components/export.d.ts +2 -0
  36. package/dist/esm/components/export.js +44 -0
  37. package/dist/esm/components/row.d.ts +2 -1
  38. package/dist/esm/components/row.js +4 -3
  39. package/dist/esm/components/useCommonClasses.d.ts +1 -1
  40. package/dist/esm/components/useCommonClasses.js +10 -6
  41. package/dist/esm/components/virtualized.d.ts +1 -1
  42. package/dist/esm/components/virtualized.js +5 -5
  43. package/dist/esm/internalState/calcProps.js +51 -36
  44. package/dist/esm/misc/csvExport.d.ts +7 -0
  45. package/dist/esm/misc/csvExport.js +11 -0
  46. package/dist/esm/table.js +6 -2
  47. package/dist/esm/types.d.ts +26 -4
  48. package/package.json +16 -13
@@ -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
  }
@@ -9,18 +9,13 @@ 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
- let inputColumns;
17
- if (props.columns instanceof Function) {
18
- inputColumns = props.columns((value, column) => (Object.assign(Object.assign({}, column), { value })));
19
- }
20
- else {
21
- inputColumns = props.columns;
22
- }
23
- const withMemoizedFunctions = useMemo(() => {
16
+ const columnCache = useRef(new Map());
17
+ return useMemo(() => {
18
+ var _a, _b;
24
19
  let id;
25
20
  if (props.id instanceof Function) {
26
21
  id = props.id;
@@ -38,33 +33,53 @@ export function calcProps(props) {
38
33
  else {
39
34
  parentId = noopParentId;
40
35
  }
41
- const columns = inputColumns.map(function ({ id, value, sortBy = (v) => (typeof v === 'number' || v instanceof Date ? v : String(v)), renderCell = asString, filterComponent, onFilterChange, }, index) {
42
- return {
43
- id: id !== null && id !== void 0 ? id : index,
44
- value,
45
- sortBy,
46
- renderCell,
47
- filterComponent,
48
- onFilterChange,
49
- };
36
+ let inputColumns;
37
+ if (props.columns instanceof Function) {
38
+ inputColumns = props.columns((value, column) => (Object.assign(Object.assign({}, column), { value })));
39
+ }
40
+ else {
41
+ inputColumns = props.columns.map((column) => (Object.assign(Object.assign({}, column), { dependecies: undefined })));
42
+ }
43
+ const newColumnCache = new Map();
44
+ const columns = inputColumns.map(function (_a, index) {
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;
50
64
  });
51
- return {
52
- id,
65
+ columnCache.current = newColumnCache;
66
+ let copy;
67
+ if (props.enableExport === true || (props.enableExport instanceof Object && props.enableExport.copy === true)) {
68
+ copy = { separator: '\t' };
69
+ }
70
+ else if (props.enableExport && props.enableExport.copy instanceof Object) {
71
+ copy = props.enableExport.copy;
72
+ }
73
+ let download;
74
+ if (props.enableExport === true || (props.enableExport instanceof Object && props.enableExport.download === true)) {
75
+ download = { sepPrefix: true };
76
+ }
77
+ else if (props.enableExport && props.enableExport.download instanceof Object) {
78
+ download = props.enableExport.download;
79
+ }
80
+ const enableExport = { copy, download };
81
+ return Object.assign(Object.assign({}, props), { id,
53
82
  parentId,
54
- hasDeferredChildren: props.hasDeferredChildren,
55
- onSortChange: props.onSortChange,
56
- onExpandedChange: props.onExpandedChange,
57
- onHiddenColumnsChange: props.onHiddenColumnsChange,
58
- debug: props.debug,
59
- columns,
60
- };
61
- }, props.dependencies);
62
- const columns = inputColumns.map(function (_a, index) {
63
- var { id, header = null, value, sortBy = (v) => (typeof v === 'number' || v instanceof Date ? v : String(v)), renderCell = (v) => v } = _a, props = __rest(_a, ["id", "header", "value", "sortBy", "renderCell"]);
64
- return Object.assign(Object.assign(Object.assign({}, props), { id: id !== null && id !== void 0 ? id : index, header,
65
- value,
66
- sortBy,
67
- renderCell }), withMemoizedFunctions.columns.find((c) => c.id === (id !== null && id !== void 0 ? id : index)));
68
- });
69
- return useMemo(() => (Object.assign(Object.assign(Object.assign({}, props), withMemoizedFunctions), { columns })), [props]);
83
+ columns, enableSelection: (_a = props.enableSelection) !== null && _a !== void 0 ? _a : true, enableColumnSelection: (_b = props.enableColumnSelection) !== null && _b !== void 0 ? _b : true, enableExport });
84
+ }, [props]);
70
85
  }
@@ -0,0 +1,7 @@
1
+ export declare type CsvExportOptions = {
2
+ sepPrefix?: boolean;
3
+ separator?: string;
4
+ quote?: string;
5
+ eol?: string;
6
+ };
7
+ export declare function csvExport(data: (string | number)[][], { sepPrefix, separator, quote, eol }?: CsvExportOptions): string;
@@ -0,0 +1,11 @@
1
+ export function csvExport(data, { sepPrefix, separator = ',', quote = '"', eol = '\n' } = {}) {
2
+ const cells = data.map((line) => line.map((value) => {
3
+ if (typeof value === 'number')
4
+ return String(value);
5
+ if (![separator, quote, eol].some((c) => value.includes(c)))
6
+ return value;
7
+ const clean = value.replace(new RegExp(quote, 'g'), `${quote}${quote}`);
8
+ return `${quote}${clean}${quote}`;
9
+ }));
10
+ return (sepPrefix ? `SEP=${separator}\n` : '') + cells.map((line) => line.join(separator)).join(eol);
11
+ }
package/dist/esm/table.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { createContext, memo, useContext } from 'react';
3
3
  import { ColumnSelection } from './components/columnSelection';
4
+ import { Export } from './components/export';
4
5
  import { FilterComponent } from './components/filterComponent';
5
6
  import { Row } from './components/row';
6
7
  import { SelectComponent } from './components/selectComponent';
@@ -43,6 +44,9 @@ const TableInner = memo(function TableInner() {
43
44
  const defaultWidth = state.useState('props.defaultWidth');
44
45
  const classes = state.useState('props.classes');
45
46
  const stickyHeader = state.useState('props.stickyHeader');
47
+ const enableSelection = state.useState('props.enableSelection');
48
+ const enableColumnSelection = state.useState('props.enableColumnSelection');
49
+ const enableExport = state.useState((state) => !!state.props.enableExport.copy || !!state.props.enableExport.download);
46
50
  (_b = (_a = state.getState().props).debug) === null || _b === void 0 ? void 0 : _b.call(_a, 'render table inner');
47
51
  return (_jsx(Virtualized, Object.assign({ className: c(commonClasses.table, classes === null || classes === void 0 ? void 0 : classes.table), style: {
48
52
  gridTemplateColumns: [
@@ -52,8 +56,8 @@ const TableInner = memo(function TableInner() {
52
56
  ...activeColumns.map((column) => { var _a, _b; return (_b = (_a = column.width) !== null && _a !== void 0 ? _a : defaultWidth) !== null && _b !== void 0 ? _b : 'max-content'; }),
53
57
  fullWidth === 'left' || fullWidth === true ? 'auto' : '0',
54
58
  ].join(' '),
55
- }, 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: [_jsx(SelectComponent, {}, void 0), _jsx(ColumnSelection, {}, void 0)] }), void 0), activeColumns.map((column) => {
59
+ }, 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) => {
56
60
  var _a;
57
61
  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));
58
- }), _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));
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, startIndex) => itemIds.map((itemId, index) => _jsx(Row, { itemId: itemId, rowIndex: startIndex + index }, itemId)) }), void 0));
59
63
  });
@@ -1,5 +1,6 @@
1
- import { CSSProperties, DependencyList, ReactNode } from 'react';
1
+ import { CSSProperties, ReactNode } from 'react';
2
2
  import { Filter } from './components/filterComponent';
3
+ import { CsvExportOptions } from './misc/csvExport';
3
4
  export declare type Sort = {
4
5
  columnId: string | number;
5
6
  direction: SortDirection;
@@ -32,15 +33,20 @@ export declare type TableProps<T> = {
32
33
  onHiddenColumnsChange?: (hiddenColumns: Set<Id>) => void;
33
34
  defaultWidth?: string;
34
35
  fullWidth?: boolean | 'left' | 'right';
35
- dependencies?: DependencyList;
36
36
  stickyHeader?: boolean;
37
37
  virtual?: boolean | {
38
38
  rowHeight?: number;
39
39
  initalRowHeight?: number;
40
40
  throttleScroll?: number;
41
+ overscan?: number;
42
+ overscanBottom?: number;
43
+ overscanTop?: number;
41
44
  };
42
45
  text?: {
43
46
  deselectAll?: string;
47
+ exportTitle?: string;
48
+ exportCopy?: string;
49
+ exportDownload?: string;
44
50
  };
45
51
  classes?: {
46
52
  table?: string;
@@ -49,12 +55,25 @@ export declare type TableProps<T> = {
49
55
  evenCell?: string;
50
56
  oddCell?: string;
51
57
  };
58
+ wrapCell?: (cell: ReactNode, item: T) => ReactNode;
52
59
  debug?: (...output: any) => void;
60
+ enableSelection?: boolean;
61
+ enableColumnSelection?: boolean;
62
+ enableExport?: boolean | {
63
+ copy?: boolean | CsvExportOptions;
64
+ download?: boolean | CsvExportOptions;
65
+ };
53
66
  };
54
- export declare type InternalTableProps<T> = Omit<TableProps<T>, 'id' | 'parentId' | 'columns'> & {
67
+ export declare type InternalTableProps<T> = Omit<TableProps<T>, 'id' | 'parentId' | 'columns' | 'enableSelection' | 'enableColumnSelection' | 'enableExport'> & {
55
68
  id: (item: T) => Id;
56
69
  parentId?: (item: T) => Id | undefined;
57
70
  columns: InternalColumn<T, unknown>[];
71
+ enableSelection: boolean;
72
+ enableColumnSelection: boolean;
73
+ enableExport: {
74
+ copy?: CsvExportOptions;
75
+ download?: CsvExportOptions;
76
+ };
58
77
  };
59
78
  export declare type TableItem<T = unknown> = T & {
60
79
  id: Id;
@@ -66,6 +85,7 @@ export declare type Column<T, V> = {
66
85
  header?: ReactNode;
67
86
  value: (item: T) => V;
68
87
  renderCell?: (value: V, item: T) => ReactNode;
88
+ exportCell?: (value: V, item: T) => string | number;
69
89
  sortBy?: ((value: V, item: T) => unknown) | ((value: V) => unknown)[];
70
90
  filterComponent?: ReactNode;
71
91
  defaultFilter?: Filter<V>;
@@ -80,10 +100,12 @@ export declare type Column<T, V> = {
80
100
  evenCell?: string;
81
101
  oddCell?: string;
82
102
  };
103
+ /** If the column definition changes, supply parameters that it depends on. If not set, the column will not update */
104
+ dependencies?: any[];
83
105
  };
84
106
  export declare type InternalColumn<T, V> = Required<Omit<Column<T, V>, 'id'> & {
85
107
  id: Id;
86
- }, 'header' | 'stringValue' | 'sortBy' | 'renderValue' | 'renderCell'>;
108
+ }, 'header' | 'stringValue' | 'sortBy' | 'renderValue' | 'renderCell' | 'exportCell'>;
87
109
  declare type Required<T, S> = T & {
88
110
  [P in keyof T as P extends S ? P : never]-?: T[P];
89
111
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "schummar-table",
3
3
  "repository": "schummar/schummar-table",
4
- "version": "0.1.0",
4
+ "version": "0.3.1",
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 start:*",
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:*",
@@ -36,27 +36,30 @@
36
36
  "peerDependencies": {
37
37
  "@material-ui/core": ">=4.11.4",
38
38
  "@material-ui/icons": ">=4.11.2",
39
- "@types/react": ">=16.8.0",
40
- "immer": ">=9.0.0",
39
+ "@types/react": ">=17.0.11",
40
+ "immer": ">=9.0.3",
41
41
  "react": ">=16.8.0",
42
42
  "schummar-state": ">=0.0.36"
43
43
  },
44
44
  "devDependencies": {
45
- "@testing-library/react": "^11.2.7",
46
- "@typescript-eslint/eslint-plugin": "^4.28.0",
47
- "@typescript-eslint/parser": "^4.28.0",
45
+ "@testing-library/react": "^12.1.2",
46
+ "@types/react": "*",
47
+ "@typescript-eslint/eslint-plugin": "^5.4.0",
48
+ "@typescript-eslint/parser": "^5.4.0",
48
49
  "ava": "^3.15.0",
49
- "eslint": "^7.29.0",
50
- "global-jsdom": "^8.1.0",
51
- "jsdom": "^17.0.0",
50
+ "eslint": "^8.2.0",
51
+ "global-jsdom": "^8.3.0",
52
+ "immer": "*",
53
+ "jsdom": "^18.1.0",
52
54
  "npm-run-all": "^4.1.5",
53
55
  "nyc": "^15.1.0",
54
- "prettier": "^2.3.1",
56
+ "prettier": "^2.4.1",
55
57
  "react": "^17.0.2",
56
58
  "react-dom": "^17.0.2",
57
59
  "rimraf": "^3.0.2",
58
- "ts-node": "^9.1.1",
59
- "typescript": "^4.3.4"
60
+ "schummar-state": "*",
61
+ "ts-node": "^10.4.0",
62
+ "typescript": "^4.5.2"
60
63
  },
61
64
  "files": [
62
65
  "dist"