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
@@ -16,14 +16,9 @@ const react_1 = require("react");
16
16
  const helpers_1 = require("../misc/helpers");
17
17
  const noopParentId = () => undefined;
18
18
  function calcProps(props) {
19
- let inputColumns;
20
- if (props.columns instanceof Function) {
21
- inputColumns = props.columns((value, column) => (Object.assign(Object.assign({}, column), { value })));
22
- }
23
- else {
24
- inputColumns = props.columns;
25
- }
26
- const withMemoizedFunctions = react_1.useMemo(() => {
19
+ const columnCache = (0, react_1.useRef)(new Map());
20
+ return (0, react_1.useMemo)(() => {
21
+ var _a, _b;
27
22
  let id;
28
23
  if (props.id instanceof Function) {
29
24
  id = props.id;
@@ -41,34 +36,54 @@ function calcProps(props) {
41
36
  else {
42
37
  parentId = noopParentId;
43
38
  }
44
- const columns = inputColumns.map(function ({ id, value, sortBy = (v) => (typeof v === 'number' || v instanceof Date ? v : String(v)), renderCell = helpers_1.asString, filterComponent, onFilterChange, }, index) {
45
- return {
46
- id: id !== null && id !== void 0 ? id : index,
47
- value,
48
- sortBy,
49
- renderCell,
50
- filterComponent,
51
- onFilterChange,
52
- };
39
+ let inputColumns;
40
+ if (props.columns instanceof Function) {
41
+ inputColumns = props.columns((value, column) => (Object.assign(Object.assign({}, column), { value })));
42
+ }
43
+ else {
44
+ inputColumns = props.columns.map((column) => (Object.assign(Object.assign({}, column), { dependecies: undefined })));
45
+ }
46
+ const newColumnCache = new Map();
47
+ const columns = inputColumns.map(function (_a, index) {
48
+ var _b;
49
+ var { id, header = null, renderCell = helpers_1.asString, exportCell = helpers_1.asString, sortBy = (v) => (typeof v === 'number' || v instanceof Date ? v : String(v)), dependencies = [] } = _a, props = __rest(_a, ["id", "header", "renderCell", "exportCell", "sortBy", "dependencies"]);
50
+ const [depsInCache, columnInCache] = (_b = columnCache.current.get(id !== null && id !== void 0 ? id : index)) !== null && _b !== void 0 ? _b : [];
51
+ let column;
52
+ if (depsInCache &&
53
+ columnInCache &&
54
+ depsInCache.length === dependencies.length &&
55
+ depsInCache.every((x, i) => dependencies[i] === x)) {
56
+ column = columnInCache;
57
+ }
58
+ else {
59
+ column = Object.assign({ id: id !== null && id !== void 0 ? id : index, header,
60
+ renderCell,
61
+ exportCell,
62
+ sortBy,
63
+ dependencies }, props);
64
+ }
65
+ newColumnCache.set(id !== null && id !== void 0 ? id : index, [dependencies, column]);
66
+ return column;
53
67
  });
54
- return {
55
- id,
68
+ columnCache.current = newColumnCache;
69
+ let copy;
70
+ if (props.enableExport === true || (props.enableExport instanceof Object && props.enableExport.copy === true)) {
71
+ copy = { separator: '\t' };
72
+ }
73
+ else if (props.enableExport && props.enableExport.copy instanceof Object) {
74
+ copy = props.enableExport.copy;
75
+ }
76
+ let download;
77
+ if (props.enableExport === true || (props.enableExport instanceof Object && props.enableExport.download === true)) {
78
+ download = { sepPrefix: true };
79
+ }
80
+ else if (props.enableExport && props.enableExport.download instanceof Object) {
81
+ download = props.enableExport.download;
82
+ }
83
+ const enableExport = { copy, download };
84
+ return Object.assign(Object.assign({}, props), { id,
56
85
  parentId,
57
- hasDeferredChildren: props.hasDeferredChildren,
58
- onSortChange: props.onSortChange,
59
- onExpandedChange: props.onExpandedChange,
60
- onHiddenColumnsChange: props.onHiddenColumnsChange,
61
- debug: props.debug,
62
- columns,
63
- };
64
- }, props.dependencies);
65
- const columns = inputColumns.map(function (_a, index) {
66
- 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"]);
67
- return Object.assign(Object.assign(Object.assign({}, props), { id: id !== null && id !== void 0 ? id : index, header,
68
- value,
69
- sortBy,
70
- renderCell }), withMemoizedFunctions.columns.find((c) => c.id === (id !== null && id !== void 0 ? id : index)));
71
- });
72
- return react_1.useMemo(() => (Object.assign(Object.assign(Object.assign({}, props), withMemoizedFunctions), { columns })), [props]);
86
+ columns, enableSelection: (_a = props.enableSelection) !== null && _a !== void 0 ? _a : true, enableColumnSelection: (_b = props.enableColumnSelection) !== null && _b !== void 0 ? _b : true, enableExport });
87
+ }, [props]);
73
88
  }
74
89
  exports.calcProps = calcProps;
@@ -4,7 +4,7 @@ exports.cleanupState = void 0;
4
4
  const react_1 = require("react");
5
5
  const helpers_1 = require("../misc/helpers");
6
6
  function cleanupState(state) {
7
- react_1.useEffect(() => state.addReaction((state) => [state.props.columns, state.itemsById, state.activeItemsById, state.activeColumns], ([columns, itemsById, activeItemsById, activeColumns], draft) => {
7
+ (0, react_1.useEffect)(() => state.addReaction((state) => [state.props.columns, state.itemsById, state.activeItemsById, state.activeColumns], ([columns, itemsById, activeItemsById, activeColumns], draft) => {
8
8
  var _a, _b, _c, _d, _e, _f;
9
9
  const columnIds = new Set(columns.map((column) => column.id));
10
10
  const activeColumnIds = new Set(activeColumns.map((column) => column.id));
@@ -26,13 +26,13 @@ function cleanupState(state) {
26
26
  }
27
27
  if (draft.props.items) {
28
28
  // Remove selection for non active items
29
- const newSelection = helpers_1.intersect(draft.selection, activeItemsById);
29
+ const newSelection = (0, helpers_1.intersect)(draft.selection, activeItemsById);
30
30
  if (newSelection.size !== draft.selection.size) {
31
31
  draft.selection = newSelection;
32
32
  (_d = (_c = draft.props).onSelectionChange) === null || _d === void 0 ? void 0 : _d.call(_c, newSelection);
33
33
  }
34
34
  // Remove expanded for non existing items
35
- const newExpanded = helpers_1.intersect(draft.expanded, itemsById);
35
+ const newExpanded = (0, helpers_1.intersect)(draft.expanded, itemsById);
36
36
  if (newExpanded.size < draft.expanded.size) {
37
37
  draft.expanded = newExpanded;
38
38
  (_f = (_e = draft.props).onExpandedChange) === null || _f === void 0 ? void 0 : _f.call(_e, newExpanded);
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.filterColumns = void 0;
4
4
  const react_1 = require("react");
5
5
  function filterColumns(state) {
6
- react_1.useEffect(() => state.addReaction((state) => [state.props.columns, state.hiddenColumns], ([columns, hiddenColumns], draft) => {
6
+ (0, react_1.useEffect)(() => state.addReaction((state) => [state.props.columns, state.hiddenColumns], ([columns, hiddenColumns], draft) => {
7
7
  draft.activeColumns = columns.filter((column) => !hiddenColumns.has(column.id));
8
8
  }, { runNow: true }), [state]);
9
9
  }
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.syncSelections = void 0;
4
4
  const react_1 = require("react");
5
5
  function syncSelections(state) {
6
- react_1.useEffect(() => state.addReaction((state) => [state.props.selectSyncChildren, state.selection, state.activeItems], ([selectSyncChildren, selection, activeItems], state) => {
6
+ (0, react_1.useEffect)(() => state.addReaction((state) => [state.props.selectSyncChildren, state.selection, state.activeItems], ([selectSyncChildren, selection, activeItems], state) => {
7
7
  var _a, _b;
8
8
  if (!selectSyncChildren)
9
9
  return;
@@ -10,8 +10,8 @@ const cleanupState_1 = require("./cleanupState");
10
10
  const filterColumns_1 = require("./filterColumns");
11
11
  const syncSelections_1 = require("./syncSelections");
12
12
  function useTableState(_props) {
13
- const props = calcProps_1.calcProps(_props);
14
- const state = react_1.useMemo(() => {
13
+ const props = (0, calcProps_1.calcProps)(_props);
14
+ const state = (0, react_1.useMemo)(() => {
15
15
  var _a, _b, _c, _d;
16
16
  return new react_2.Store({
17
17
  props,
@@ -36,13 +36,13 @@ function useTableState(_props) {
36
36
  lastSelectedId: undefined,
37
37
  });
38
38
  }, []);
39
- filterColumns_1.filterColumns(state);
40
- calcItems_1.calcItems(state);
41
- syncSelections_1.syncSelections(state);
42
- cleanupState_1.cleanupState(state);
43
- react_1.useEffect(() => {
39
+ (0, filterColumns_1.filterColumns)(state);
40
+ (0, calcItems_1.calcItems)(state);
41
+ (0, syncSelections_1.syncSelections)(state);
42
+ (0, cleanupState_1.cleanupState)(state);
43
+ (0, react_1.useEffect)(() => {
44
44
  state.update((state) => {
45
- state.props = immer_1.castDraft(props);
45
+ state.props = (0, immer_1.castDraft)(props);
46
46
  if (props.sort)
47
47
  state.sort = props.sort;
48
48
  if (props.selection)
@@ -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,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.csvExport = void 0;
4
+ function csvExport(data, { sepPrefix, separator = ',', quote = '"', eol = '\n' } = {}) {
5
+ const cells = data.map((line) => line.map((value) => {
6
+ if (typeof value === 'number')
7
+ return String(value);
8
+ if (![separator, quote, eol].some((c) => value.includes(c)))
9
+ return value;
10
+ const clean = value.replace(new RegExp(quote, 'g'), `${quote}${quote}`);
11
+ return `${quote}${clean}${quote}`;
12
+ }));
13
+ return (sepPrefix ? `SEP=${separator}\n` : '') + cells.map((line) => line.join(separator)).join(eol);
14
+ }
15
+ exports.csvExport = csvExport;
@@ -65,7 +65,7 @@ const getDescendants = (...items) => {
65
65
  return result;
66
66
  };
67
67
  exports.getDescendants = getDescendants;
68
- const c = (...classNames) => exports.flatMap(classNames, (item) => {
68
+ const c = (...classNames) => (0, exports.flatMap)(classNames, (item) => {
69
69
  if (item === undefined)
70
70
  return [];
71
71
  if (typeof item === 'string')
@@ -4,7 +4,7 @@ exports.termMatch = exports.textMatch = void 0;
4
4
  const textMatch = (text, query) => {
5
5
  text = text.toLowerCase();
6
6
  query = query.toLowerCase();
7
- return query.split(/\s+/).every((part) => exports.termMatch(text, part));
7
+ return query.split(/\s+/).every((part) => (0, exports.termMatch)(text, part));
8
8
  };
9
9
  exports.textMatch = textMatch;
10
10
  const termMatch = (text, query) => {
package/dist/cjs/table.js CHANGED
@@ -4,6 +4,7 @@ exports.Table = exports.useColumnContext = exports.useTableContext = exports.Col
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const columnSelection_1 = require("./components/columnSelection");
7
+ const export_1 = require("./components/export");
7
8
  const filterComponent_1 = require("./components/filterComponent");
8
9
  const row_1 = require("./components/row");
9
10
  const selectComponent_1 = require("./components/selectComponent");
@@ -12,17 +13,17 @@ const useCommonClasses_1 = require("./components/useCommonClasses");
12
13
  const virtualized_1 = require("./components/virtualized");
13
14
  const useTableState_1 = require("./internalState/useTableState");
14
15
  const helpers_1 = require("./misc/helpers");
15
- exports.TableContext = react_1.createContext(null);
16
- exports.ColumnContext = react_1.createContext(null);
16
+ exports.TableContext = (0, react_1.createContext)(null);
17
+ exports.ColumnContext = (0, react_1.createContext)(null);
17
18
  function useTableContext() {
18
- const value = react_1.useContext(exports.TableContext);
19
+ const value = (0, react_1.useContext)(exports.TableContext);
19
20
  if (!value)
20
21
  throw Error('No table context available');
21
22
  return value;
22
23
  }
23
24
  exports.useTableContext = useTableContext;
24
25
  function useColumnContext() {
25
- const value = react_1.useContext(exports.ColumnContext);
26
+ const value = (0, react_1.useContext)(exports.ColumnContext);
26
27
  if (value === null)
27
28
  throw Error('No column context available');
28
29
  return value;
@@ -30,14 +31,14 @@ function useColumnContext() {
30
31
  exports.useColumnContext = useColumnContext;
31
32
  function Table(props) {
32
33
  var _a, _b;
33
- const state = useTableState_1.useTableState(props);
34
+ const state = (0, useTableState_1.useTableState)(props);
34
35
  (_b = (_a = state.getState().props).debug) === null || _b === void 0 ? void 0 : _b.call(_a, 'render table');
35
- return (jsx_runtime_1.jsx(exports.TableContext.Provider, Object.assign({ value: state }, { children: jsx_runtime_1.jsx(TableInner, {}, void 0) }), void 0));
36
+ return ((0, jsx_runtime_1.jsx)(exports.TableContext.Provider, Object.assign({ value: state }, { children: (0, jsx_runtime_1.jsx)(TableInner, {}, void 0) }), void 0));
36
37
  }
37
38
  exports.Table = Table;
38
- const TableInner = react_1.memo(function TableInner() {
39
+ const TableInner = (0, react_1.memo)(function TableInner() {
39
40
  var _a, _b;
40
- const commonClasses = useCommonClasses_1.useCommonClasses();
41
+ const commonClasses = (0, useCommonClasses_1.useCommonClasses)();
41
42
  const state = useTableContext();
42
43
  const fullWidth = state.useState('props.fullWidth');
43
44
  const activeColumns = state.useState((state) => state.activeColumns.map((column) => ({
@@ -49,8 +50,11 @@ const TableInner = react_1.memo(function TableInner() {
49
50
  const defaultWidth = state.useState('props.defaultWidth');
50
51
  const classes = state.useState('props.classes');
51
52
  const stickyHeader = state.useState('props.stickyHeader');
53
+ const enableSelection = state.useState('props.enableSelection');
54
+ const enableColumnSelection = state.useState('props.enableColumnSelection');
55
+ const enableExport = state.useState((state) => !!state.props.enableExport.copy || !!state.props.enableExport.download);
52
56
  (_b = (_a = state.getState().props).debug) === null || _b === void 0 ? void 0 : _b.call(_a, 'render table inner');
53
- return (jsx_runtime_1.jsx(virtualized_1.Virtualized, Object.assign({ className: helpers_1.c(commonClasses.table, classes === null || classes === void 0 ? void 0 : classes.table), style: {
57
+ return ((0, jsx_runtime_1.jsx)(virtualized_1.Virtualized, Object.assign({ className: (0, helpers_1.c)(commonClasses.table, classes === null || classes === void 0 ? void 0 : classes.table), style: {
54
58
  gridTemplateColumns: [
55
59
  //
56
60
  fullWidth === 'right' || fullWidth === true ? 'auto' : '0',
@@ -58,8 +62,8 @@ const TableInner = react_1.memo(function TableInner() {
58
62
  ...activeColumns.map((column) => { var _a, _b; return (_b = (_a = column.width) !== null && _a !== void 0 ? _a : defaultWidth) !== null && _b !== void 0 ? _b : 'max-content'; }),
59
63
  fullWidth === 'left' || fullWidth === true ? 'auto' : '0',
60
64
  ].join(' '),
61
- }, header: jsx_runtime_1.jsxs(jsx_runtime_1.Fragment, { children: [jsx_runtime_1.jsx("div", { className: helpers_1.c(commonClasses.headerFill, { [commonClasses.sticky]: !!stickyHeader }, classes === null || classes === void 0 ? void 0 : classes.headerCell) }, void 0), jsx_runtime_1.jsxs("div", Object.assign({ className: helpers_1.c(commonClasses.headerCell, { [commonClasses.sticky]: !!stickyHeader }, classes === null || classes === void 0 ? void 0 : classes.headerCell) }, { children: [jsx_runtime_1.jsx(selectComponent_1.SelectComponent, {}, void 0), jsx_runtime_1.jsx(columnSelection_1.ColumnSelection, {}, void 0)] }), void 0), activeColumns.map((column) => {
65
+ }, header: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: (0, helpers_1.c)(commonClasses.headerFill, { [commonClasses.sticky]: !!stickyHeader }, classes === null || classes === void 0 ? void 0 : classes.headerCell) }, void 0), (0, jsx_runtime_1.jsxs)("div", Object.assign({ className: (0, helpers_1.c)(commonClasses.headerCell, { [commonClasses.sticky]: !!stickyHeader }, classes === null || classes === void 0 ? void 0 : classes.headerCell) }, { children: [enableSelection && (0, jsx_runtime_1.jsx)(selectComponent_1.SelectComponent, {}, void 0), enableColumnSelection && (0, jsx_runtime_1.jsx)(columnSelection_1.ColumnSelection, {}, void 0), enableExport && (0, jsx_runtime_1.jsx)(export_1.Export, {}, void 0)] }), void 0), activeColumns.map((column) => {
62
66
  var _a;
63
- return (jsx_runtime_1.jsx(exports.ColumnContext.Provider, Object.assign({ value: column.id }, { children: jsx_runtime_1.jsxs("div", Object.assign({ className: helpers_1.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_runtime_1.jsx(sortComponent_1.SortComponent, { children: column.header }, void 0), jsx_runtime_1.jsx(filterComponent_1.FilterComponent, {}, void 0)] }), column.id) }), column.id));
64
- }), jsx_runtime_1.jsx("div", { className: helpers_1.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_runtime_1.jsx(row_1.Row, { itemId: itemId }, itemId)) }), void 0));
67
+ return ((0, jsx_runtime_1.jsx)(exports.ColumnContext.Provider, Object.assign({ value: column.id }, { children: (0, jsx_runtime_1.jsxs)("div", Object.assign({ className: (0, helpers_1.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: [(0, jsx_runtime_1.jsx)(sortComponent_1.SortComponent, { children: column.header }, void 0), (0, jsx_runtime_1.jsx)(filterComponent_1.FilterComponent, {}, void 0)] }), column.id) }), column.id));
68
+ }), (0, jsx_runtime_1.jsx)("div", { className: (0, helpers_1.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) => (0, jsx_runtime_1.jsx)(row_1.Row, { itemId: itemId, rowIndex: startIndex + index }, itemId)) }), void 0));
65
69
  });
@@ -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
  };
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import { Id } from '..';
3
- export declare const Cell: React.MemoExoticComponent<(<T>({ itemId }: {
3
+ export declare const Cell: React.MemoExoticComponent<(<T>({ itemId, rowIndex }: {
4
4
  itemId: Id;
5
- }) => JSX.Element)>;
5
+ rowIndex: number;
6
+ }) => JSX.Element | null)>;
@@ -1,23 +1,28 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { memo } from 'react';
3
3
  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 { className, content } = state.useState((state) => {
13
- const item = state.activeItemsById.get(itemId);
14
- const column = state.activeColumns.find((column) => column.id === columnId);
15
- const index = item ? state.activeItems.indexOf(item) : -1;
16
- return {
17
- className: c(calcClassName(state.props.classes, index), calcClassName(column === null || column === void 0 ? void 0 : column.classes, index)),
18
- content: item && column && column.renderCell(column.value(item), item),
19
- };
20
- }, [itemId, columnId]);
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;
21
18
  (_b = (_a = state.getState().props).debug) === null || _b === void 0 ? void 0 : _b.call(_a, 'render cell', itemId, columnId);
22
- return _jsx("div", Object.assign({ className: c(commonClasses.cell, className) }, { children: content }), void 0);
19
+ const className = c(calcClassName(classes, rowIndex), calcClassName(column === null || column === void 0 ? void 0 : column.classes, 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);
23
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: 'center' } }, { 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));
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
  }
@@ -24,11 +24,10 @@ export function DefaultFilterComponent({ filterBy: _filterBy, options: _options,
24
24
  const classes = useClasses();
25
25
  const state = useTableContext();
26
26
  const columnId = useColumnContext();
27
- const deps = state.useState('props.dependencies');
28
27
  const filterBy = useCallback((value, item) => {
29
28
  const values = _filterBy ? _filterBy(value, item) : value;
30
29
  return values instanceof Array ? values : [values];
31
- }, deps !== null && deps !== void 0 ? deps : [_filterBy]);
30
+ }, [_filterBy]);
32
31
  const { text, options, filter } = state.useState((state) => {
33
32
  const column = state.activeColumns.find((column) => column.id === columnId);
34
33
  const _filter = state.filters.get(columnId);
@@ -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));
@@ -0,0 +1,2 @@
1
+ /// <reference types="react" />
2
+ export declare function Export<T>(): JSX.Element;
@@ -0,0 +1,44 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Button, IconButton, makeStyles, Popover, Typography } from '@material-ui/core';
3
+ import { AssignmentReturn, CloudDownload } from '@material-ui/icons';
4
+ import { useState } from 'react';
5
+ import { csvExport } from '../misc/csvExport';
6
+ import { useTableContext } from '../table';
7
+ const useClasses = makeStyles((theme) => ({
8
+ dialog: {
9
+ padding: theme.spacing(2),
10
+ display: 'grid',
11
+ justifyItems: 'stretch',
12
+ '& > *': {
13
+ justifyContent: 'start',
14
+ },
15
+ },
16
+ }));
17
+ export function Export() {
18
+ const classes = useClasses();
19
+ const [anchor, setAnchor] = useState(null);
20
+ const state = useTableContext();
21
+ const textTitle = state.useState('props.text.exportTitle');
22
+ const textCopy = state.useState('props.text.exportCopy');
23
+ const textDownload = state.useState('props.text.exportDownload');
24
+ const generate = (options) => {
25
+ const { activeColumns, activeItems } = state.getState();
26
+ const data = [
27
+ activeColumns.map((column) => String(column.id)),
28
+ ...activeItems.map((item) => activeColumns.map((column) => column.exportCell(column.value(item), item))),
29
+ ];
30
+ return csvExport(data, options);
31
+ };
32
+ const copy = () => {
33
+ navigator.clipboard.writeText(generate(state.getState().props.enableExport.copy));
34
+ };
35
+ const download = () => {
36
+ const a = document.createElement('a');
37
+ a.href = 'data:text/csv;charset=utf-8,' + encodeURIComponent(generate(state.getState().props.enableExport.download));
38
+ a.download = 'export.csv';
39
+ document.body.appendChild(a);
40
+ a.click();
41
+ document.body.removeChild(a);
42
+ };
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
+ }
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import { Id, InternalColumn } from '../types';
3
3
  export declare const calcClassName: (classes: InternalColumn<any, any>['classes'] | undefined, index: number) => string;
4
- export declare const Row: React.MemoExoticComponent<(<T>({ itemId }: {
4
+ export declare const Row: React.MemoExoticComponent<(<T>({ itemId, rowIndex }: {
5
5
  itemId: Id;
6
+ rowIndex: number;
6
7
  }) => JSX.Element | null)>;
@@ -7,12 +7,12 @@ import { ExpandComponent } from './expandComponent';
7
7
  import { SelectComponent } from './selectComponent';
8
8
  import { useCommonClasses } from './useCommonClasses';
9
9
  export const calcClassName = (classes, index) => c(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 });
10
- export const Row = memo(function Row({ itemId }) {
10
+ export const Row = memo(function Row({ itemId, rowIndex }) {
11
11
  var _a, _b;
12
12
  const commonClasses = useCommonClasses();
13
13
  const state = useTableContext();
14
14
  const divRef = useRef(null);
15
- const { className, indent, hasChildren, hasDeferredChildren, columnIds } = state.useState((state) => {
15
+ const { className, indent, hasChildren, hasDeferredChildren, columnIds, enableSelection } = state.useState((state) => {
16
16
  var _a, _b;
17
17
  const item = state.activeItemsById.get(itemId);
18
18
  const index = !item ? -1 : state.activeItems.indexOf(item);
@@ -22,6 +22,7 @@ export const Row = memo(function Row({ itemId }) {
22
22
  hasChildren: !!(item === null || item === void 0 ? void 0 : item.children.length),
23
23
  hasDeferredChildren: item && ((_b = (_a = state.props).hasDeferredChildren) === null || _b === void 0 ? void 0 : _b.call(_a, item)),
24
24
  columnIds: state.activeColumns.map((column) => column.id),
25
+ enableSelection: state.props.enableSelection,
25
26
  };
26
27
  }, [itemId]);
27
28
  useEffect(() => {
@@ -39,5 +40,5 @@ export const Row = memo(function Row({ itemId }) {
39
40
  return () => o.disconnect();
40
41
  }, [divRef.current]);
41
42
  (_b = (_a = state.getState().props).debug) === null || _b === void 0 ? void 0 : _b.call(_a, 'render row', itemId);
42
- 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), _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));
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, rowIndex: rowIndex }, void 0) }), columnId))), _jsx("div", { className: c(commonClasses.cellFill, className) }, void 0)] }, void 0));
43
44
  });
@@ -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.5, 1),
4
- display: 'grid',
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: 'none', gridTemplateColumns: 'minmax(0, 1fr) max-content', background: theme.palette.primary.main, color: theme.palette.primary.contrastText, fontWeight: 'bold', '&:not(:first-child)': {
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
- background: theme.palette.primary.main,
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;