@etsoo/materialui 1.5.71 → 1.5.73

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 (61) hide show
  1. package/__tests__/ReactAppTests.tsx +12 -7
  2. package/__tests__/{ResponsePage.tsx → ResponsivePage.tsx} +11 -5
  3. package/__tests__/SelectEx.tsx +1 -1
  4. package/lib/cjs/DataGridEx.d.ts +8 -1
  5. package/lib/cjs/DataGridEx.js +71 -56
  6. package/lib/cjs/DataGridRenderers.d.ts +1 -1
  7. package/lib/cjs/DataGridRenderers.js +1 -1
  8. package/lib/cjs/MUUtils.d.ts +0 -9
  9. package/lib/cjs/MUUtils.js +0 -26
  10. package/lib/cjs/MobileListItemRenderer.d.ts +2 -2
  11. package/lib/cjs/MobileListItemRenderer.js +3 -4
  12. package/lib/cjs/ResponsibleContainer.d.ts +9 -13
  13. package/lib/cjs/ResponsibleContainer.js +19 -58
  14. package/lib/cjs/ScrollerListEx.d.ts +23 -23
  15. package/lib/cjs/ScrollerListEx.js +32 -84
  16. package/lib/cjs/TableEx.d.ts +7 -0
  17. package/lib/cjs/TableEx.js +6 -12
  18. package/lib/cjs/pages/DataGridPage.js +3 -32
  19. package/lib/cjs/pages/FixedListPage.js +5 -34
  20. package/lib/cjs/pages/ListPage.js +1 -29
  21. package/lib/cjs/pages/ResponsivePage.d.ts +9 -13
  22. package/lib/cjs/uses/useGridCacheInitLoad.d.ts +2 -0
  23. package/lib/cjs/uses/useGridCacheInitLoad.js +41 -0
  24. package/lib/cjs/uses/useListCacheInitLoad.d.ts +2 -0
  25. package/lib/cjs/uses/useListCacheInitLoad.js +38 -0
  26. package/lib/mjs/DataGridEx.d.ts +8 -1
  27. package/lib/mjs/DataGridEx.js +71 -56
  28. package/lib/mjs/DataGridRenderers.d.ts +1 -1
  29. package/lib/mjs/DataGridRenderers.js +1 -1
  30. package/lib/mjs/MUUtils.d.ts +0 -9
  31. package/lib/mjs/MUUtils.js +0 -26
  32. package/lib/mjs/MobileListItemRenderer.d.ts +2 -2
  33. package/lib/mjs/MobileListItemRenderer.js +3 -4
  34. package/lib/mjs/ResponsibleContainer.d.ts +9 -13
  35. package/lib/mjs/ResponsibleContainer.js +19 -58
  36. package/lib/mjs/ScrollerListEx.d.ts +23 -23
  37. package/lib/mjs/ScrollerListEx.js +32 -84
  38. package/lib/mjs/TableEx.d.ts +7 -0
  39. package/lib/mjs/TableEx.js +6 -12
  40. package/lib/mjs/pages/DataGridPage.js +3 -32
  41. package/lib/mjs/pages/FixedListPage.js +5 -34
  42. package/lib/mjs/pages/ListPage.js +1 -29
  43. package/lib/mjs/pages/ResponsivePage.d.ts +9 -13
  44. package/lib/mjs/uses/useGridCacheInitLoad.d.ts +2 -0
  45. package/lib/mjs/uses/useGridCacheInitLoad.js +35 -0
  46. package/lib/mjs/uses/useListCacheInitLoad.d.ts +2 -0
  47. package/lib/mjs/uses/useListCacheInitLoad.js +32 -0
  48. package/package.json +18 -19
  49. package/src/DataGridEx.tsx +155 -109
  50. package/src/DataGridRenderers.tsx +2 -1
  51. package/src/MUUtils.ts +0 -33
  52. package/src/MobileListItemRenderer.tsx +4 -4
  53. package/src/ResponsibleContainer.tsx +50 -111
  54. package/src/ScrollerListEx.tsx +141 -229
  55. package/src/TableEx.tsx +20 -12
  56. package/src/pages/DataGridPage.tsx +3 -49
  57. package/src/pages/FixedListPage.tsx +5 -49
  58. package/src/pages/ListPage.tsx +0 -43
  59. package/src/pages/ResponsivePage.tsx +16 -21
  60. package/src/uses/useGridCacheInitLoad.ts +55 -0
  61. package/src/uses/useListCacheInitLoad.ts +51 -0
@@ -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, rowHeight = 53, 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, rowHeight: rowHeight, 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, margins, style }: ScrollerListExItemRendererProps<T>, renderer: (data: T) => [
12
12
  string,
13
13
  string | undefined,
14
14
  React.ReactNode | (ListItemReact | boolean)[],
@@ -11,16 +11,15 @@ import CardContent from "@mui/material/CardContent";
11
11
  * @param renderer Renderer for card content
12
12
  * @returns Component
13
13
  */
14
- export function MobileListItemRenderer({ data, itemHeight, margins }, renderer) {
14
+ export function MobileListItemRenderer({ data, margins, style }, renderer) {
15
15
  // Loading
16
16
  if (data == null)
17
17
  return _jsx(LinearProgress, {});
18
18
  // Elements
19
19
  const [title, subheader, actions, children, cardActions] = renderer(data);
20
20
  return (_jsxs(Card, { sx: {
21
- height: itemHeight,
22
21
  ...margins
23
- }, children: [_jsx(CardHeader, { sx: { paddingBottom: 0.5 }, action: Array.isArray(actions) ? (_jsx(MoreFab, { iconButton: true, size: "small", anchorOrigin: {
22
+ }, style: style, children: [_jsx(CardHeader, { sx: { paddingBottom: 0.5 }, action: Array.isArray(actions) ? (_jsx(MoreFab, { iconButton: true, size: "small", anchorOrigin: {
24
23
  vertical: "bottom",
25
24
  horizontal: "right"
26
25
  }, transformOrigin: {
@@ -31,6 +30,6 @@ export function MobileListItemRenderer({ data, itemHeight, margins }, renderer)
31
30
  subheader: { variant: "caption" }
32
31
  } }), _jsx(CardContent, { sx: {
33
32
  paddingTop: 0,
34
- paddingBottom: cardActions == null ? Reflect.get(margins, "marginBottom") : 0
33
+ paddingBottom: cardActions == null ? Reflect.get(margins, "marginBottom") ?? 0 : 0
35
34
  }, children: children }), cardActions] }));
36
35
  }
@@ -1,13 +1,12 @@
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 { ScrollerListExProps } from "./ScrollerListEx";
6
5
  import { SxProps, Theme } from "@mui/material/styles";
7
6
  /**
8
7
  * ResponsibleContainer props
9
8
  */
10
- export type ResponsibleContainerProps<T extends object, F> = Omit<DataGridExProps<T>, "height" | "itemKey" | "loadData" | "mRef" | "onScroll" | "onItemsRendered" | "onInitLoad" | "onUpdateRows"> & {
9
+ export type ResponsibleContainerProps<T extends object, F> = Omit<DataGridExProps<T>, "height" | "loadData" | "mRef" | "onInitLoad" | "onUpdateRows" | "rowHeight"> & {
11
10
  /**
12
11
  * Height will be deducted
13
12
  * @param height Current calcuated height
@@ -41,18 +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;
52
- /**
53
- * Item size, a function indicates its a variable size list
54
- */
55
- itemSize: ScrollerListExItemSize;
46
+ itemRenderer?: ScrollerListExProps<T>["itemRenderer"];
56
47
  /**
57
48
  * Load data callback
58
49
  */
@@ -60,7 +51,7 @@ export type ResponsibleContainerProps<T extends object, F> = Omit<DataGridExProp
60
51
  /**
61
52
  * Methods
62
53
  */
63
- mRef?: React.MutableRefObject<GridMethodRef<T> | undefined>;
54
+ mRef?: React.RefObject<GridMethodRef<T> | undefined>;
64
55
  /**
65
56
  * Element ready callback
66
57
  */
@@ -77,6 +68,11 @@ export type ResponsibleContainerProps<T extends object, F> = Omit<DataGridExProp
77
68
  * Quick action for double click or click under mobile
78
69
  */
79
70
  quickAction?: (data: T) => void;
71
+ /**
72
+ * Row height
73
+ * @param isGrid Is displaying as DataGrid
74
+ */
75
+ rowHeight?: number | [number, number] | (<B extends boolean>(isGrid: B) => B extends true ? DataGridExProps<T>["rowHeight"] : ScrollerListExProps<T>["rowHeight"]);
80
76
  /**
81
77
  * Size ready to read miliseconds span
82
78
  */
@@ -26,7 +26,7 @@ function defaultContainerBoxSx(paddings, hasField, _dataGrid) {
26
26
  */
27
27
  export function ResponsibleContainer(props) {
28
28
  // Destruct
29
- const { adjustHeight, adjustFabHeight, cacheKey, cacheMinutes = 15, columns, containerBoxSx = defaultContainerBoxSx, elementReady, fields, fieldTemplate, height, loadData, mRef, paddings = MUGlobal.pagePaddings, pullToRefresh = true, quickAction, sizeReadyMiliseconds = 0, searchBarHeight = 45.6, searchBarBottom = 8, searchBarTop, ...rest } = props;
29
+ const { adjustHeight, adjustFabHeight, cacheKey, cacheMinutes = 15, columns, containerBoxSx = defaultContainerBoxSx, elementReady, fields, fieldTemplate, height, loadData, mRef, paddings = MUGlobal.pagePaddings, pullToRefresh = true, quickAction, rowHeight, sizeReadyMiliseconds = 0, searchBarHeight = 45.6, searchBarBottom = 8, searchBarTop, ...rest } = props;
30
30
  // Labels
31
31
  const labels = Labels.CommonPage;
32
32
  // Refs
@@ -36,6 +36,8 @@ export function ResponsibleContainer(props) {
36
36
  if (ref == null)
37
37
  return;
38
38
  state.ref = ref;
39
+ if (ref.element && elementReady)
40
+ elementReady(ref.element, true);
39
41
  });
40
42
  // Screen size detection
41
43
  const showDataGrid = useMediaQuery("(min-width:600px)");
@@ -52,6 +54,16 @@ export function ResponsibleContainer(props) {
52
54
  state.mounted = true;
53
55
  return loadData(GridUtils.createLoader(props, fieldTemplate, cacheKey, false), lastItem);
54
56
  };
57
+ const getRowHeight = React.useCallback((isGrid) => {
58
+ if (rowHeight == null)
59
+ return undefined;
60
+ else if (typeof rowHeight === "number")
61
+ return isGrid ? undefined : rowHeight;
62
+ else if (Array.isArray(rowHeight))
63
+ return rowHeight[isGrid ? 0 : 1];
64
+ else
65
+ return rowHeight(isGrid);
66
+ }, [rowHeight]);
55
67
  // Search data
56
68
  const searchData = useSearchParamsWithCache(cacheKey);
57
69
  // On submit callback
@@ -77,44 +89,6 @@ export function ResponsibleContainer(props) {
77
89
  state.rect = rect;
78
90
  return false;
79
91
  });
80
- const onInitLoad = (ref) => {
81
- // Avoid repeatedly load from cache
82
- if (refs.current.initLoaded || !cacheKey)
83
- return undefined;
84
- // Cache data
85
- const cacheData = GridUtils.getCacheData(cacheKey, cacheMinutes);
86
- if (cacheData) {
87
- const { rows, state } = cacheData;
88
- GridUtils.mergeSearchData(state, searchData);
89
- // Scroll position
90
- const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
91
- if (scrollData) {
92
- if ("resetAfterColumnIndex" in ref) {
93
- const { scrollLeft, scrollTop } = JSON.parse(scrollData);
94
- globalThis.setTimeout(() => ref.scrollTo({ scrollLeft, scrollTop }), 0);
95
- }
96
- else {
97
- const { scrollOffset } = JSON.parse(scrollData);
98
- globalThis.setTimeout(() => ref.scrollTo(scrollOffset), 0);
99
- }
100
- }
101
- // Update flag value
102
- refs.current.initLoaded = true;
103
- // Return cached rows and state
104
- return [rows, state];
105
- }
106
- return undefined;
107
- };
108
- const onListScroll = (props) => {
109
- if (!cacheKey || !refs.current.initLoaded)
110
- return;
111
- sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
112
- };
113
- const onGridScroll = (props) => {
114
- if (!cacheKey || !refs.current.initLoaded)
115
- return;
116
- sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
117
- };
118
92
  // Rect
119
93
  const rect = dimensions[0][2];
120
94
  // Create list
@@ -144,26 +118,13 @@ export function ResponsibleContainer(props) {
144
118
  if (adjustFabHeight)
145
119
  heightLocal = adjustFabHeight(heightLocal, showDataGrid);
146
120
  if (showDataGrid) {
147
- // Delete
148
- delete rest.itemRenderer;
149
- return (_jsx(Box, { className: "DataGridBox", children: _jsx(DataGridEx, { autoLoad: !hasFields, height: heightLocal, width: rect.width, loadData: localLoadData, mRef: mRefs, onDoubleClick: (_, data) => quickAction && quickAction(data), outerRef: (element) => {
150
- if (element != null && elementReady)
151
- elementReady(element, true);
152
- }, onScroll: onGridScroll, columns: columns, onUpdateRows: GridUtils.getUpdateRowsHandler(cacheKey), onInitLoad: onInitLoad, ...rest }) }));
121
+ // Remove useless props
122
+ const { itemRenderer, ...gridProps } = rest;
123
+ return (_jsx(Box, { className: "DataGridBox", children: _jsx(DataGridEx, { autoLoad: !hasFields, height: heightLocal, width: rect.width, loadData: localLoadData, mRef: mRefs, onDoubleClick: (_, data) => quickAction && quickAction(data), columns: columns, rowHeight: getRowHeight(true), ...gridProps }) }));
153
124
  }
154
- // Delete
155
- delete rest.checkable;
156
- delete rest.borderRowsCount;
157
- delete rest.bottomHeight;
158
- delete rest.footerItemRenderer;
159
- delete rest.headerHeight;
160
- delete rest.hideFooter;
161
- delete rest.hoverColor;
162
- delete rest.selectable;
163
- return (_jsx(Box, { className: "ListBox", sx: { height: heightLocal }, children: _jsx(ScrollerListEx, { autoLoad: !hasFields, height: heightLocal, loadData: localLoadData, onUpdateRows: GridUtils.getUpdateRowsHandler(cacheKey), onInitLoad: onInitLoad, mRef: mRefs, onClick: (event, data) => quickAction && ReactUtils.isSafeClick(event) && quickAction(data), oRef: (element) => {
164
- if (element != null && elementReady)
165
- elementReady(element, false);
166
- }, onScroll: onListScroll, ...rest }) }));
125
+ // Remove useless props
126
+ const { checkable, borderRowsCount, bottomHeight, footerItemRenderer, headerHeight, hideFooter, hoverColor, selectable, onCellsRendered, ...listProps } = rest;
127
+ return (_jsx(Box, { className: "ListBox", sx: { height: heightLocal }, children: _jsx(ScrollerListEx, { autoLoad: !hasFields, height: heightLocal, loadData: localLoadData, mRef: mRefs, onClick: (event, data) => quickAction && ReactUtils.isSafeClick(event) && quickAction(data), rowHeight: getRowHeight(false), ...listProps }) }));
167
128
  })();
168
129
  const searchBar = React.useMemo(() => {
169
130
  if (!hasFields ||
@@ -1,55 +1,55 @@
1
1
  import { ScrollerListProps } from "@etsoo/react";
2
2
  import React from "react";
3
- import { ListChildComponentProps } from "react-window";
4
3
  import { MouseEventWithDataHandler } from "./MUGlobal";
5
4
  /**
6
5
  * Extended ScrollerList inner item renderer props
7
6
  */
8
- export interface ScrollerListExInnerItemRendererProps<T> extends ListChildComponentProps<T> {
7
+ export type ScrollerListExItemRendererProps<T> = {
9
8
  /**
10
- * Item selected
9
+ * Row index
11
10
  */
12
- selected: boolean;
11
+ index: number;
13
12
  /**
14
- * Item height
13
+ * Row data
15
14
  */
16
- itemHeight: number;
15
+ data: T;
17
16
  /**
18
- * Item space
17
+ * Style
19
18
  */
20
- space: number;
19
+ style: React.CSSProperties;
21
20
  /**
22
21
  * Default margins
23
22
  */
24
23
  margins: object;
25
- }
26
- /**
27
- * Extended ScrollerList ItemSize type
28
- * 1. Callback function
29
- * 2. Static sets
30
- * 3. Dynamic left & right margin calculation
31
- */
32
- export type ScrollerListExItemSize = ((index: number) => [number, number] | [number, number, object]) | [number, number] | [number, object, (number | string)?];
24
+ /**
25
+ * Item selected
26
+ */
27
+ selected: boolean;
28
+ };
33
29
  /**
34
30
  * Extended ScrollerList Props
35
31
  */
36
- export type ScrollerListExProps<T extends object> = Omit<ScrollerListProps<T>, "itemRenderer" | "itemSize"> & {
32
+ export type ScrollerListExProps<T extends object> = Omit<ScrollerListProps<T>, "rowComponent" | "rowHeight" | "onClick" | "onDoubleClick" | "onInitLoad"> & Partial<Pick<ScrollerListProps<T>, "rowHeight">> & {
37
33
  /**
38
34
  * Alternating colors for odd/even rows
39
35
  */
40
36
  alternatingColors?: [string?, string?];
41
37
  /**
42
- * Inner item renderer
38
+ * Cache key
43
39
  */
44
- innerItemRenderer: (props: ScrollerListExInnerItemRendererProps<T>) => React.ReactNode;
40
+ cacheKey?: string;
45
41
  /**
46
- * Item renderer
42
+ * Cache minutes
47
43
  */
48
- itemRenderer?: (props: ListChildComponentProps<T>) => React.ReactElement;
44
+ cacheMinutes?: number;
49
45
  /**
50
- * Item size, a function indicates its a variable size list
46
+ * Cell margins, default to half of MUGlobal.pagePaddings
47
+ */
48
+ cellMargins?: object;
49
+ /**
50
+ * Item renderer
51
51
  */
52
- itemSize: ScrollerListExItemSize;
52
+ itemRenderer?: (props: ScrollerListExItemRendererProps<T>) => React.ReactNode;
53
53
  /**
54
54
  * Double click handler
55
55
  */