@etsoo/materialui 1.5.71 → 1.5.72

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 (58) hide show
  1. package/__tests__/ReactAppTests.tsx +12 -7
  2. package/__tests__/SelectEx.tsx +1 -1
  3. package/lib/cjs/DataGridEx.d.ts +8 -1
  4. package/lib/cjs/DataGridEx.js +71 -56
  5. package/lib/cjs/DataGridRenderers.d.ts +1 -1
  6. package/lib/cjs/DataGridRenderers.js +1 -1
  7. package/lib/cjs/MUUtils.d.ts +0 -9
  8. package/lib/cjs/MUUtils.js +0 -26
  9. package/lib/cjs/MobileListItemRenderer.d.ts +2 -2
  10. package/lib/cjs/ResponsibleContainer.d.ts +2 -7
  11. package/lib/cjs/ResponsibleContainer.js +8 -57
  12. package/lib/cjs/ScrollerListEx.d.ts +24 -9
  13. package/lib/cjs/ScrollerListEx.js +35 -38
  14. package/lib/cjs/TableEx.d.ts +7 -0
  15. package/lib/cjs/TableEx.js +6 -12
  16. package/lib/cjs/pages/DataGridPage.js +3 -32
  17. package/lib/cjs/pages/FixedListPage.js +5 -34
  18. package/lib/cjs/pages/ListPage.js +1 -29
  19. package/lib/cjs/pages/ResponsivePage.d.ts +2 -7
  20. package/lib/cjs/uses/useGridCacheInitLoad.d.ts +2 -0
  21. package/lib/cjs/uses/useGridCacheInitLoad.js +41 -0
  22. package/lib/cjs/uses/useListCacheInitLoad.d.ts +2 -0
  23. package/lib/cjs/uses/useListCacheInitLoad.js +38 -0
  24. package/lib/mjs/DataGridEx.d.ts +8 -1
  25. package/lib/mjs/DataGridEx.js +71 -56
  26. package/lib/mjs/DataGridRenderers.d.ts +1 -1
  27. package/lib/mjs/DataGridRenderers.js +1 -1
  28. package/lib/mjs/MUUtils.d.ts +0 -9
  29. package/lib/mjs/MUUtils.js +0 -26
  30. package/lib/mjs/MobileListItemRenderer.d.ts +2 -2
  31. package/lib/mjs/ResponsibleContainer.d.ts +2 -7
  32. package/lib/mjs/ResponsibleContainer.js +8 -57
  33. package/lib/mjs/ScrollerListEx.d.ts +24 -9
  34. package/lib/mjs/ScrollerListEx.js +35 -38
  35. package/lib/mjs/TableEx.d.ts +7 -0
  36. package/lib/mjs/TableEx.js +6 -12
  37. package/lib/mjs/pages/DataGridPage.js +3 -32
  38. package/lib/mjs/pages/FixedListPage.js +5 -34
  39. package/lib/mjs/pages/ListPage.js +1 -29
  40. package/lib/mjs/pages/ResponsivePage.d.ts +2 -7
  41. package/lib/mjs/uses/useGridCacheInitLoad.d.ts +2 -0
  42. package/lib/mjs/uses/useGridCacheInitLoad.js +35 -0
  43. package/lib/mjs/uses/useListCacheInitLoad.d.ts +2 -0
  44. package/lib/mjs/uses/useListCacheInitLoad.js +32 -0
  45. package/package.json +18 -19
  46. package/src/DataGridEx.tsx +151 -108
  47. package/src/DataGridRenderers.tsx +2 -1
  48. package/src/MUUtils.ts +0 -33
  49. package/src/MobileListItemRenderer.tsx +2 -2
  50. package/src/ResponsibleContainer.tsx +21 -94
  51. package/src/ScrollerListEx.tsx +109 -121
  52. package/src/TableEx.tsx +20 -12
  53. package/src/pages/DataGridPage.tsx +3 -49
  54. package/src/pages/FixedListPage.tsx +5 -49
  55. package/src/pages/ListPage.tsx +0 -43
  56. package/src/pages/ResponsivePage.tsx +3 -11
  57. package/src/uses/useGridCacheInitLoad.ts +55 -0
  58. package/src/uses/useListCacheInitLoad.ts +51 -0
@@ -34,7 +34,7 @@ function TableEx(props) {
34
34
  // Theme
35
35
  const theme = (0, styles_1.useTheme)();
36
36
  // Destruct
37
- const { alternatingColors = [theme.palette.action.hover, undefined], autoLoad = true, columns, defaultOrderBy, headerColors = [undefined, undefined], idField = "id", loadBatchSize, loadData, maxHeight, mRef, onSelectChange, rowHeight = 53, otherHeight = 110, threshold, ...rest } = props;
37
+ const { alternatingColors = [theme.palette.action.hover, undefined], autoLoad = true, columns, defaultOrderBy, headerColors = [undefined, undefined], idField = "id", loadBatchSize, loadData, maxHeight, mRef, onDataChange, onSelectChange, rowHeight = 53, otherHeight = 110, threshold, ...rest } = props;
38
38
  const selectable = onSelectChange != null;
39
39
  // Rows per page
40
40
  let rowsPerPageLocal;
@@ -90,6 +90,9 @@ function TableEx(props) {
90
90
  });
91
91
  };
92
92
  react_2.default.useImperativeHandle(mRef, () => ({
93
+ get element() {
94
+ return null;
95
+ },
93
96
  delete(index) {
94
97
  const item = rows.at(index);
95
98
  if (item) {
@@ -104,20 +107,11 @@ function TableEx(props) {
104
107
  newRows.splice(start, 0, item);
105
108
  setRows(newRows);
106
109
  },
107
- /**
108
- * Refresh data
109
- */
110
110
  refresh() {
111
111
  loadDataLocal();
112
112
  },
113
- /**
114
- * Reset
115
- */
116
113
  reset,
117
- scrollToRef(scrollOffset) {
118
- // Not implemented
119
- },
120
- scrollToItemRef(index) {
114
+ scrollToRow(param) {
121
115
  // Not implemented
122
116
  }
123
117
  }), []);
@@ -291,7 +285,7 @@ function TableEx(props) {
291
285
  rowIndex,
292
286
  columnIndex,
293
287
  cellProps,
294
- setItems
288
+ triggerChange: () => onDataChange?.(rows, rowIndex, columnIndex)
295
289
  })) : ((0, jsx_runtime_1.jsx)(react_2.default.Fragment, { children: "\u00A0" }));
296
290
  return ((0, jsx_runtime_1.jsx)(TableCell_1.default, { ...cellProps, children: child }, `${rowId}${columnIndex}`));
297
291
  })] }, rowId));
@@ -33,9 +33,10 @@ function DataGridPage(props) {
33
33
  if (ref == null)
34
34
  return;
35
35
  states.ref = ref;
36
+ if (ref.element)
37
+ setStates({ element: ref.element });
36
38
  //setStates({ ref });
37
39
  });
38
- const initLoadedRef = react_2.default.useRef(null);
39
40
  // On submit callback
40
41
  const onSubmit = (data, _reset) => {
41
42
  setStates({ data });
@@ -45,33 +46,6 @@ function DataGridPage(props) {
45
46
  };
46
47
  // Search data
47
48
  const searchData = (0, react_1.useSearchParamsWithCache)(cacheKey);
48
- const onInitLoad = (ref) => {
49
- // Avoid repeatedly load from cache
50
- if (initLoadedRef.current || !cacheKey)
51
- return undefined;
52
- // Cache data
53
- const cacheData = GridUtils_1.GridUtils.getCacheData(cacheKey, cacheMinutes);
54
- if (cacheData) {
55
- const { rows, state } = cacheData;
56
- GridUtils_1.GridUtils.mergeSearchData(state, searchData);
57
- // Scroll position
58
- const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
59
- if (scrollData) {
60
- const { scrollLeft, scrollTop } = JSON.parse(scrollData);
61
- globalThis.setTimeout(() => ref.scrollTo({ scrollLeft, scrollTop }), 0);
62
- }
63
- // Update flag value
64
- initLoadedRef.current = true;
65
- // Return cached rows and state
66
- return [rows, state];
67
- }
68
- return undefined;
69
- };
70
- const onGridScroll = (props) => {
71
- if (!cacheKey || !initLoadedRef.current)
72
- return;
73
- sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
74
- };
75
49
  // Watch container
76
50
  const { dimensions } = (0, react_1.useDimensions)(1, undefined, sizeReadyMiliseconds);
77
51
  const rect = dimensions[0][2];
@@ -96,10 +70,7 @@ function DataGridPage(props) {
96
70
  const gridHeight = states.height;
97
71
  if (gridHeight == null)
98
72
  return;
99
- return ((0, jsx_runtime_1.jsx)(DataGridEx_1.DataGridEx, { autoLoad: false, height: gridHeight, loadData: localLoadData, mRef: refs, onUpdateRows: GridUtils_1.GridUtils.getUpdateRowsHandler(cacheKey), onInitLoad: onInitLoad, onScroll: onGridScroll, outerRef: (element) => {
100
- if (element != null)
101
- setStates({ element });
102
- }, ...rest }));
73
+ return ((0, jsx_runtime_1.jsx)(DataGridEx_1.DataGridEx, { autoLoad: false, height: gridHeight, loadData: localLoadData, mRef: refs, ...rest }));
103
74
  }, [states.height]);
104
75
  const { ref, data } = states;
105
76
  react_2.default.useEffect(() => {
@@ -25,7 +25,6 @@ function FixedListPage(props) {
25
25
  pageProps.paddings ??= MUGlobal_1.MUGlobal.pagePaddings;
26
26
  // States
27
27
  const [states] = react_2.default.useState({});
28
- const initLoadedRef = react_2.default.useRef(null);
29
28
  // Scroll container
30
29
  const [scrollContainer, updateScrollContainer] = react_2.default.useState();
31
30
  const refs = (0, react_1.useCombinedRefs)(mRef, (ref) => {
@@ -33,6 +32,8 @@ function FixedListPage(props) {
33
32
  return;
34
33
  const first = states.ref == null;
35
34
  states.ref = ref;
35
+ if (ref.element)
36
+ updateScrollContainer(ref.element);
36
37
  if (first)
37
38
  reset();
38
39
  });
@@ -49,35 +50,6 @@ function FixedListPage(props) {
49
50
  const localLoadData = (props, lastItem) => {
50
51
  return loadData(GridUtils_1.GridUtils.createLoader(props, fieldTemplate, cacheKey, false), lastItem);
51
52
  };
52
- // Search data
53
- const searchData = (0, react_1.useSearchParamsWithCache)(cacheKey);
54
- const onInitLoad = (ref) => {
55
- // Avoid repeatedly load from cache
56
- if (initLoadedRef.current || !cacheKey)
57
- return undefined;
58
- // Cache data
59
- const cacheData = GridUtils_1.GridUtils.getCacheData(cacheKey, cacheMinutes);
60
- if (cacheData) {
61
- const { rows, state } = cacheData;
62
- GridUtils_1.GridUtils.mergeSearchData(state, searchData);
63
- // Scroll position
64
- const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
65
- if (scrollData) {
66
- const { scrollOffset } = JSON.parse(scrollData);
67
- globalThis.setTimeout(() => ref.scrollTo(scrollOffset), 0);
68
- }
69
- // Update flag value
70
- initLoadedRef.current = true;
71
- // Return cached rows and state
72
- return [rows, state];
73
- }
74
- return undefined;
75
- };
76
- const onListScroll = (props) => {
77
- if (!cacheKey || !initLoadedRef.current)
78
- return;
79
- sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
80
- };
81
53
  // Watch container
82
54
  const { dimensions } = (0, react_1.useDimensions)(1, undefined, sizeReadyMiliseconds);
83
55
  const rect = dimensions[0][2];
@@ -92,12 +64,11 @@ function FixedListPage(props) {
92
64
  : adjustHeight(height, rect);
93
65
  return ((0, jsx_runtime_1.jsx)(Box_1.default, { id: "list-container", sx: {
94
66
  height: height + "px"
95
- }, children: (0, jsx_runtime_1.jsx)(ScrollerListEx_1.ScrollerListEx, { autoLoad: false, height: height, loadData: localLoadData, mRef: refs, onUpdateRows: GridUtils_1.GridUtils.getUpdateRowsHandler(cacheKey), onInitLoad: onInitLoad, onScroll: onListScroll, oRef: (element) => {
96
- if (element != null)
97
- updateScrollContainer(element);
98
- }, ...rest }) }));
67
+ }, children: (0, jsx_runtime_1.jsx)(ScrollerListEx_1.ScrollerListEx, { autoLoad: false, height: height, loadData: localLoadData, mRef: refs, ...rest }) }));
99
68
  }
100
69
  }, [rect]);
70
+ // Search data
71
+ const searchData = (0, react_1.useSearchParamsWithCache)(cacheKey);
101
72
  const f = typeof fields == "function" ? fields(searchData ?? {}) : fields;
102
73
  const { paddings, ...pageRest } = pageProps;
103
74
  // Layout
@@ -33,7 +33,6 @@ function ListPage(props) {
33
33
  if (first)
34
34
  reset();
35
35
  });
36
- const initLoadedRef = react_2.default.useRef(null);
37
36
  const reset = () => {
38
37
  if (states.data == null || states.ref == null)
39
38
  return;
@@ -52,36 +51,9 @@ function ListPage(props) {
52
51
  const rect = dimensions[0][2];
53
52
  // Search data
54
53
  const searchData = (0, react_1.useSearchParamsWithCache)(cacheKey);
55
- const onInitLoad = (ref) => {
56
- // Avoid repeatedly load from cache
57
- if (initLoadedRef.current || !cacheKey)
58
- return undefined;
59
- // Cache data
60
- const cacheData = GridUtils_1.GridUtils.getCacheData(cacheKey, cacheMinutes);
61
- if (cacheData) {
62
- const { rows, state } = cacheData;
63
- GridUtils_1.GridUtils.mergeSearchData(state, searchData);
64
- // Scroll position
65
- const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
66
- if (scrollData) {
67
- const { scrollOffset } = JSON.parse(scrollData);
68
- globalThis.setTimeout(() => ref.scrollTo(scrollOffset), 0);
69
- }
70
- // Update flag value
71
- initLoadedRef.current = true;
72
- // Return cached rows and state
73
- return [rows, state];
74
- }
75
- return undefined;
76
- };
77
- const onListScroll = (props) => {
78
- if (!cacheKey || !initLoadedRef.current)
79
- return;
80
- sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
81
- };
82
54
  const f = typeof fields == "function" ? fields(searchData ?? {}) : fields;
83
55
  // Layout
84
56
  return ((0, jsx_runtime_1.jsx)(CommonPage_1.CommonPage, { ...pageProps, scrollContainer: globalThis, children: (0, jsx_runtime_1.jsxs)(Stack_1.default, { children: [(0, jsx_runtime_1.jsx)(Box_1.default, { ref: dimensions[0][0], sx: {
85
57
  paddingBottom: pageProps.paddings
86
- }, children: rect && rect.width > 100 && ((0, jsx_runtime_1.jsx)(SearchBar_1.SearchBar, { fields: f, onSubmit: onSubmit, top: searchBarTop, width: rect.width })) }), (0, jsx_runtime_1.jsx)(ScrollerListEx_1.ScrollerListEx, { autoLoad: false, loadData: localLoadData, onUpdateRows: GridUtils_1.GridUtils.getUpdateRowsHandler(cacheKey), onInitLoad: onInitLoad, onScroll: onListScroll, mRef: refs, ...rest })] }) }));
58
+ }, children: rect && rect.width > 100 && ((0, jsx_runtime_1.jsx)(SearchBar_1.SearchBar, { fields: f, onSubmit: onSubmit, top: searchBarTop, width: rect.width })) }), (0, jsx_runtime_1.jsx)(ScrollerListEx_1.ScrollerListEx, { autoLoad: false, loadData: localLoadData, mRef: refs, ...rest })] }) }));
87
59
  }
@@ -1,7 +1,6 @@
1
1
  import React from "react";
2
2
  import type { DataGridPageProps } from "./DataGridPageProps";
3
- import type { ScrollerListExInnerItemRendererProps, ScrollerListExItemSize } from "../ScrollerListEx";
4
- import { ListChildComponentProps } from "react-window";
3
+ import type { ScrollerListExItemSize, ScrollerListExProps } from "../ScrollerListEx";
5
4
  import { GridMethodRef } from "@etsoo/react";
6
5
  import type { OperationMessageHandlerAll } from "../messages/OperationMessageHandler";
7
6
  /**
@@ -19,14 +18,10 @@ export type ResponsePageProps<T extends object, F> = DataGridPageProps<T, F> & {
19
18
  * Min width to show Datagrid
20
19
  */
21
20
  dataGridMinWidth?: number;
22
- /**
23
- * Inner item renderer
24
- */
25
- innerItemRenderer: (props: ScrollerListExInnerItemRendererProps<T>) => React.ReactNode;
26
21
  /**
27
22
  * Item renderer
28
23
  */
29
- itemRenderer?: (props: ListChildComponentProps<T>) => React.ReactElement;
24
+ itemRenderer?: ScrollerListExProps<T>["itemRenderer"];
30
25
  /**
31
26
  * Item size, a function indicates its a variable size list
32
27
  */
@@ -0,0 +1,2 @@
1
+ import { ScrollerGridProps } from "@etsoo/react";
2
+ export declare function useGridCacheInitLoad<T extends object>(cacheKey: string | undefined, cacheMinutes: number): ScrollerGridProps<T>["onInitLoad"];
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.useGridCacheInitLoad = useGridCacheInitLoad;
7
+ const react_1 = require("@etsoo/react");
8
+ const react_2 = __importDefault(require("react"));
9
+ const GridUtils_1 = require("../GridUtils");
10
+ const shared_1 = require("@etsoo/shared");
11
+ function useGridCacheInitLoad(cacheKey, cacheMinutes) {
12
+ // Reference
13
+ const ref = react_2.default.useRef(null);
14
+ // Search data
15
+ const searchData = (0, react_1.useSearchParamsWithCache)(cacheKey);
16
+ // Avoid repeatedly load from cache
17
+ if (ref.current || !cacheKey)
18
+ return undefined;
19
+ // Cache data
20
+ const cacheData = GridUtils_1.GridUtils.getCacheData(cacheKey, cacheMinutes);
21
+ if (cacheData) {
22
+ const { rows, state } = cacheData;
23
+ GridUtils_1.GridUtils.mergeSearchData(state, searchData);
24
+ // Update flag value
25
+ ref.current = true;
26
+ return (ref) => {
27
+ // Scroll position
28
+ const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
29
+ if (scrollData) {
30
+ const data = JSON.parse(scrollData);
31
+ shared_1.ExtendUtils.waitFor(() => ref.scrollToCell({
32
+ rowIndex: data.rowStartIndex,
33
+ columnIndex: data.columnStartIndex
34
+ }), 100);
35
+ }
36
+ // Return cached rows and state
37
+ return [rows, state];
38
+ };
39
+ }
40
+ return undefined;
41
+ }
@@ -0,0 +1,2 @@
1
+ import { ScrollerListProps } from "@etsoo/react";
2
+ export declare function useListCacheInitLoad<T extends object>(cacheKey: string | undefined, cacheMinutes: number): ScrollerListProps<T>["onInitLoad"];
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.useListCacheInitLoad = useListCacheInitLoad;
7
+ const react_1 = require("@etsoo/react");
8
+ const react_2 = __importDefault(require("react"));
9
+ const GridUtils_1 = require("../GridUtils");
10
+ const shared_1 = require("@etsoo/shared");
11
+ function useListCacheInitLoad(cacheKey, cacheMinutes) {
12
+ // Reference
13
+ const ref = react_2.default.useRef(null);
14
+ // Search data
15
+ const searchData = (0, react_1.useSearchParamsWithCache)(cacheKey);
16
+ // Avoid repeatedly load from cache
17
+ if (ref.current || !cacheKey)
18
+ return undefined;
19
+ // Cache data
20
+ const cacheData = GridUtils_1.GridUtils.getCacheData(cacheKey, cacheMinutes);
21
+ if (cacheData) {
22
+ const { rows, state } = cacheData;
23
+ GridUtils_1.GridUtils.mergeSearchData(state, searchData);
24
+ // Update flag value
25
+ ref.current = true;
26
+ return (ref) => {
27
+ // Scroll position
28
+ const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
29
+ if (scrollData) {
30
+ const data = JSON.parse(scrollData);
31
+ shared_1.ExtendUtils.waitFor(() => ref.scrollToRow({ index: data.startIndex }), 100);
32
+ }
33
+ // Return cached rows and state
34
+ return [rows, state];
35
+ };
36
+ }
37
+ return undefined;
38
+ }
@@ -14,7 +14,7 @@ export type DataGridExFooterItemRendererProps<T extends object> = {
14
14
  /**
15
15
  * Extended DataGrid with VariableSizeGrid props
16
16
  */
17
- export type DataGridExProps<T extends object, P extends GridJsonData = GridLoadDataProps> = Omit<ScrollerGridProps<T, P>, "itemRenderer" | "columnCount" | "columnWidth" | "width"> & {
17
+ export type DataGridExProps<T extends object, P extends GridJsonData = GridLoadDataProps> = Omit<ScrollerGridProps<T, P>, "cellComponent" | "columnCount" | "columnWidth" | "onClick" | "onDoubleClick" | "onInitLoad" | "width"> & {
18
18
  /**
19
19
  * Alternating colors for odd/even rows
20
20
  */
@@ -70,6 +70,13 @@ export type DataGridExProps<T extends object, P extends GridJsonData = GridLoadD
70
70
  * Click handler
71
71
  */
72
72
  onClick?: MouseEventWithDataHandler<T>;
73
+ /**
74
+ * Data change handler
75
+ * @param rows Rows
76
+ * @param rowIndex Row index
77
+ * @param columnIndex Column index
78
+ */
79
+ onDataChange?: (rows: T[], rowIndex: number, columnIndex: number) => void;
73
80
  /**
74
81
  * Selectable to support hover over and out effect and row clickable
75
82
  * @default true
@@ -9,6 +9,8 @@ import Box from "@mui/material/Box";
9
9
  import TableSortLabel from "@mui/material/TableSortLabel";
10
10
  import Checkbox from "@mui/material/Checkbox";
11
11
  import Paper from "@mui/material/Paper";
12
+ import { GridUtils } from "./GridUtils";
13
+ import { useGridCacheInitLoad } from "./uses/useGridCacheInitLoad";
12
14
  // Borders
13
15
  const boldBorder = "2px solid rgba(224, 224, 224, 1)";
14
16
  const thinBorder = "1px solid rgba(224, 224, 224, 1)";
@@ -128,7 +130,7 @@ export function DataGridEx(props) {
128
130
  }) }));
129
131
  }
130
132
  // Destruct
131
- const { alternatingColors = [theme.palette.grey[100], undefined], borderRowsCount, bottomHeight = 53, checkable = false, className, columns, defaultOrderBy, height, headerHeight = 56, headerRenderer = defaultHeaderRenderer, footerRenderer = defaultFooterRenderer, footerItemRenderer = DataGridRenderers.defaultFooterItemRenderer, hideFooter = false, hoverColor = "#f6f9fb", idField = "id", mRef = React.createRef(), onClick, onDoubleClick, selectable = true, selectedColor = "#edf4fb", width, ...rest } = props;
133
+ const { alternatingColors = [theme.palette.grey[100], undefined], borderRowsCount, bottomHeight = 53, cacheKey, cacheMinutes = 15, checkable = false, className, columns, defaultOrderBy, height, headerHeight = 56, headerRenderer = defaultHeaderRenderer, footerRenderer = defaultFooterRenderer, footerItemRenderer = DataGridRenderers.defaultFooterItemRenderer, hideFooter = false, hoverColor = "#f6f9fb", idField = "id", mRef = React.createRef(), onClick, onDataChange, onDoubleClick, onUpdateRows, selectable = true, selectedColor = "#edf4fb", width, ...rest } = props;
132
134
  if (checkable) {
133
135
  const cbColumn = {
134
136
  field: "selected", // Avoid validation from data model
@@ -161,6 +163,8 @@ export function DataGridEx(props) {
161
163
  columns.unshift(cbColumn);
162
164
  }
163
165
  }
166
+ // Init handler
167
+ const initHandler = useGridCacheInitLoad(cacheKey, cacheMinutes);
164
168
  const refs = React.useRef({});
165
169
  const mRefLocal = useCombinedRefs(mRef, (ref) => {
166
170
  if (ref == null)
@@ -219,57 +223,6 @@ export function DataGridEx(props) {
219
223
  div.classList.remove("DataGridEx-Hover");
220
224
  });
221
225
  };
222
- /**
223
- * Item renderer
224
- */
225
- const itemRenderer = ({ columnIndex, rowIndex, style, data, selectedItems, setItems }) => {
226
- // Column
227
- const { align, cellRenderer = DataGridRenderers.defaultCellRenderer, cellBoxStyle, field, type, valueFormatter, renderProps } = columns[columnIndex];
228
- // Props
229
- const formatProps = {
230
- data,
231
- field,
232
- rowIndex,
233
- columnIndex
234
- };
235
- let rowClass = `DataGridEx-Cell${rowIndex % 2}`;
236
- if (borderRowsCount != null &&
237
- borderRowsCount > 0 &&
238
- (rowIndex + 1) % borderRowsCount === 0) {
239
- rowClass += ` DataGridEx-Cell-Border`;
240
- }
241
- // Selected
242
- const selected = data != null &&
243
- (selectedRowIndex.current === rowIndex ||
244
- selectedItems.some((selectedItem) => selectedItem != null && selectedItem[idField] === data[idField]));
245
- if (selected) {
246
- rowClass += ` DataGridEx-Selected`;
247
- }
248
- // Box style
249
- const boxStyle = data == null || cellBoxStyle == null
250
- ? undefined
251
- : typeof cellBoxStyle === "function"
252
- ? cellBoxStyle(data)
253
- : cellBoxStyle;
254
- const cellProps = {
255
- className: "DataGridEx-Cell",
256
- textAlign: GridAlignGet(align, type),
257
- sx: { ...boxStyle }
258
- };
259
- const child = cellRenderer({
260
- data,
261
- field,
262
- formattedValue: valueFormatter ? valueFormatter(formatProps) : undefined,
263
- selected,
264
- type,
265
- rowIndex,
266
- columnIndex,
267
- cellProps,
268
- renderProps: typeof renderProps === "function" ? renderProps(data) : renderProps,
269
- setItems
270
- });
271
- return (_jsx("div", { className: rowClass, style: style, "data-row": rowIndex, "data-column": columnIndex, onMouseDown: selectable && !checkable ? handleMouseDown : undefined, onMouseOver: selectable ? handleMouseOver : undefined, onMouseOut: selectable ? handleMouseOut : undefined, onClick: (event) => onClick && data != null && onClick(event, data), onDoubleClick: (event) => onDoubleClick && data != null && onDoubleClick(event, data), children: _jsx(Box, { ...cellProps, onMouseEnter: handleMouseEnter, children: child }) }));
272
- };
273
226
  // Column width calculator
274
227
  const widthCalculator = React.useMemo(() => DataGridExCalColumns(columns), [columns]);
275
228
  // Column width
@@ -287,12 +240,74 @@ export function DataGridEx(props) {
287
240
  const sharedWidth = leftWidth > 0 ? leftWidth / widthCalculator.unset : 0;
288
241
  return (column.minWidth || minWidth) + sharedWidth;
289
242
  }, [columns, width]);
243
+ const onUpdateRowsHandler = React.useCallback((rows, state) => {
244
+ GridUtils.getUpdateRowsHandler(cacheKey)?.(rows, state);
245
+ onUpdateRows?.(rows, state);
246
+ }, [onUpdateRows, cacheKey]);
290
247
  // Table
291
248
  const table = React.useMemo(() => {
292
- return (_jsx(ScrollerGrid, { className: Utils.mergeClasses("DataGridEx-Body", "DataGridEx-CustomBar", className, createGridStyle(alternatingColors, selectedColor, hoverColor)), columnCount: columns.length, columnWidth: columnWidth, defaultOrderBy: defaultOrderBy, height: height -
293
- headerHeight -
294
- (hideFooter ? 0 : bottomHeight + 1) -
295
- scrollbarSize, headerRenderer: headerRenderer, idField: idField, itemRenderer: itemRenderer, footerRenderer: hideFooter ? undefined : footerRenderer, width: Math.max(width ?? 0, widthCalculator.total), mRef: mRefLocal, ...rest }));
249
+ return (_jsx(ScrollerGrid, { className: Utils.mergeClasses("DataGridEx-Body", "DataGridEx-CustomBar", className, createGridStyle(alternatingColors, selectedColor, hoverColor)), onCellsRendered: cacheKey
250
+ ? (visibleCells) => sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(visibleCells))
251
+ : undefined, onInitLoad: initHandler, onUpdateRows: onUpdateRowsHandler, cellComponent: ({ rowIndex, columnIndex, style, rows, states }) => {
252
+ // Column
253
+ const { align, cellRenderer = DataGridRenderers.defaultCellRenderer, cellBoxStyle, field, type, valueFormatter, renderProps } = columns[columnIndex];
254
+ // Data
255
+ const data = rows[rowIndex];
256
+ // Props
257
+ const formatProps = {
258
+ data,
259
+ field,
260
+ rowIndex,
261
+ columnIndex
262
+ };
263
+ let rowClass = `DataGridEx-Cell${rowIndex % 2}`;
264
+ if (borderRowsCount != null &&
265
+ borderRowsCount > 0 &&
266
+ (rowIndex + 1) % borderRowsCount === 0) {
267
+ rowClass += ` DataGridEx-Cell-Border`;
268
+ }
269
+ // Selected
270
+ const selected = data != null &&
271
+ (selectedRowIndex.current === rowIndex ||
272
+ states.selectedItems.some((selectedItem) => selectedItem != null &&
273
+ selectedItem[idField] === data[idField]));
274
+ if (selected) {
275
+ rowClass += ` DataGridEx-Selected`;
276
+ }
277
+ // Box style
278
+ const boxStyle = data == null || cellBoxStyle == null
279
+ ? undefined
280
+ : typeof cellBoxStyle === "function"
281
+ ? cellBoxStyle(data)
282
+ : cellBoxStyle;
283
+ const cellProps = {
284
+ className: "DataGridEx-Cell",
285
+ textAlign: GridAlignGet(align, type),
286
+ sx: { ...boxStyle }
287
+ };
288
+ const child = cellRenderer({
289
+ data,
290
+ field,
291
+ formattedValue: valueFormatter
292
+ ? valueFormatter(formatProps)
293
+ : undefined,
294
+ selected,
295
+ type,
296
+ rowIndex,
297
+ columnIndex,
298
+ cellProps,
299
+ renderProps: typeof renderProps === "function"
300
+ ? renderProps(data)
301
+ : renderProps,
302
+ triggerChange: () => onDataChange?.(rows, rowIndex, columnIndex)
303
+ });
304
+ return (_jsx("div", { className: rowClass, style: style, "data-row": rowIndex, "data-column": columnIndex, onMouseDown: selectable && !checkable ? handleMouseDown : undefined, onMouseOver: selectable ? handleMouseOver : undefined, onMouseOut: selectable ? handleMouseOut : undefined, onClick: (event) => onClick && data != null && onClick(event, data), onDoubleClick: (event) => onDoubleClick && data != null && onDoubleClick(event, data), children: _jsx(Box, { ...cellProps, onMouseEnter: handleMouseEnter, children: child }) }));
305
+ }, columnCount: columns.length, columnWidth: columnWidth, defaultOrderBy: defaultOrderBy, height: typeof height === "number"
306
+ ? height -
307
+ headerHeight -
308
+ (hideFooter ? 0 : bottomHeight + 1) -
309
+ scrollbarSize
310
+ : height, headerRenderer: headerRenderer, idField: idField, footerRenderer: hideFooter ? undefined : footerRenderer, width: Math.max(width ?? 0, widthCalculator.total), mRef: mRefLocal, ...rest }));
296
311
  }, [width]);
297
312
  return (_jsx(Paper, { sx: {
298
313
  fontSize: "0.875rem",
@@ -10,7 +10,7 @@ export declare namespace DataGridRenderers {
10
10
  * @param param Props
11
11
  * @returns Component
12
12
  */
13
- function defaultCellRenderer<T extends Record<string, any>>({ cellProps, data, field, formattedValue, columnIndex, type, renderProps }: GridCellRendererProps<T>): React.ReactNode;
13
+ function defaultCellRenderer<T extends Record<string, any>>({ cellProps, data, field, formattedValue, columnIndex, type, renderProps, triggerChange }: GridCellRendererProps<T>): React.ReactNode;
14
14
  /**
15
15
  * Default footer item renderer
16
16
  * @param rows Rows
@@ -15,7 +15,7 @@ export var DataGridRenderers;
15
15
  * @param param Props
16
16
  * @returns Component
17
17
  */
18
- function defaultCellRenderer({ cellProps, data, field, formattedValue, columnIndex, type, renderProps }) {
18
+ function defaultCellRenderer({ cellProps, data, field, formattedValue, columnIndex, type, renderProps, triggerChange }) {
19
19
  // Is loading
20
20
  if (data == null) {
21
21
  // First column, show loading indicator
@@ -1,5 +1,3 @@
1
- import { QueryRQ } from "@etsoo/appscript";
2
- import { IdType } from "@etsoo/shared";
3
1
  import { GridApiCommunity } from "@mui/x-data-grid/internals";
4
2
  /**
5
3
  * MU utilities
@@ -12,11 +10,4 @@ export declare namespace MUUtils {
12
10
  * @returns Results
13
11
  */
14
12
  function getGridData<T>(grid: GridApiCommunity, checkField: keyof T | ((item: T) => boolean)): T[];
15
- /**
16
- * Setup paging keysets
17
- * @param data Paging data
18
- * @param lastItem Last item of the query
19
- * @param idField Id field
20
- */
21
- function setupPagingKeysets<T, K extends IdType = number>(data: QueryRQ<K>, lastItem: T | undefined, idField: keyof T & string): QueryRQ<K>;
22
13
  }
@@ -26,30 +26,4 @@ export var MUUtils;
26
26
  return items;
27
27
  }
28
28
  MUUtils.getGridData = getGridData;
29
- /**
30
- * Setup paging keysets
31
- * @param data Paging data
32
- * @param lastItem Last item of the query
33
- * @param idField Id field
34
- */
35
- function setupPagingKeysets(data, lastItem, idField) {
36
- // If the id field is not set for ordering, add it with descending
37
- if (typeof data.queryPaging === "object") {
38
- const orderBy = (data.queryPaging.orderBy ??= []);
39
- const idUpper = idField.toUpperCase();
40
- if (!orderBy.find((o) => o.field.toUpperCase() === idUpper)) {
41
- orderBy.push({ field: idField, desc: true, unique: true });
42
- }
43
- // Set the paging keysets
44
- if (lastItem) {
45
- const keysets = orderBy.map((o) => Reflect.get(lastItem, o.field));
46
- data.queryPaging.keysets = keysets;
47
- }
48
- else {
49
- data.queryPaging.keysets = undefined;
50
- }
51
- }
52
- return data;
53
- }
54
- MUUtils.setupPagingKeysets = setupPagingKeysets;
55
29
  })(MUUtils || (MUUtils = {}));
@@ -1,6 +1,6 @@
1
1
  import { ListItemReact } from "@etsoo/react";
2
2
  import React from "react";
3
- import { ScrollerListExInnerItemRendererProps } from "./ScrollerListEx";
3
+ import { ScrollerListExItemRendererProps } from "./ScrollerListEx";
4
4
  /**
5
5
  * Default mobile list item renderer
6
6
  * @param param0 List renderer props
@@ -8,7 +8,7 @@ import { ScrollerListExInnerItemRendererProps } from "./ScrollerListEx";
8
8
  * @param renderer Renderer for card content
9
9
  * @returns Component
10
10
  */
11
- export declare function MobileListItemRenderer<T>({ data, itemHeight, margins }: ScrollerListExInnerItemRendererProps<T>, renderer: (data: T) => [
11
+ export declare function MobileListItemRenderer<T>({ data, itemHeight, margins }: ScrollerListExItemRendererProps<T>, renderer: (data: T) => [
12
12
  string,
13
13
  string | undefined,
14
14
  React.ReactNode | (ListItemReact | boolean)[],
@@ -1,8 +1,7 @@
1
1
  import React from "react";
2
- import { ListChildComponentProps } from "react-window";
3
2
  import { GridColumn, GridJsonData, GridMethodRef, GridTemplateType } from "@etsoo/react";
4
3
  import { DataGridExProps } from "./DataGridEx";
5
- import { ScrollerListExInnerItemRendererProps, ScrollerListExItemSize } from "./ScrollerListEx";
4
+ import { ScrollerListExItemSize, ScrollerListExProps } from "./ScrollerListEx";
6
5
  import { SxProps, Theme } from "@mui/material/styles";
7
6
  /**
8
7
  * ResponsibleContainer props
@@ -41,14 +40,10 @@ export type ResponsibleContainerProps<T extends object, F> = Omit<DataGridExProp
41
40
  * Grid height
42
41
  */
43
42
  height?: number;
44
- /**
45
- * Inner item renderer
46
- */
47
- innerItemRenderer: (props: ScrollerListExInnerItemRendererProps<T>) => React.ReactNode;
48
43
  /**
49
44
  * Item renderer
50
45
  */
51
- itemRenderer?: (props: ListChildComponentProps<T>) => React.ReactElement;
46
+ itemRenderer?: ScrollerListExProps<T>["itemRenderer"];
52
47
  /**
53
48
  * Item size, a function indicates its a variable size list
54
49
  */