@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.
- package/__tests__/ReactAppTests.tsx +12 -7
- package/__tests__/{ResponsePage.tsx → ResponsivePage.tsx} +11 -5
- package/__tests__/SelectEx.tsx +1 -1
- package/lib/cjs/DataGridEx.d.ts +8 -1
- package/lib/cjs/DataGridEx.js +71 -56
- package/lib/cjs/DataGridRenderers.d.ts +1 -1
- package/lib/cjs/DataGridRenderers.js +1 -1
- package/lib/cjs/MUUtils.d.ts +0 -9
- package/lib/cjs/MUUtils.js +0 -26
- package/lib/cjs/MobileListItemRenderer.d.ts +2 -2
- package/lib/cjs/MobileListItemRenderer.js +3 -4
- package/lib/cjs/ResponsibleContainer.d.ts +9 -13
- package/lib/cjs/ResponsibleContainer.js +19 -58
- package/lib/cjs/ScrollerListEx.d.ts +23 -23
- package/lib/cjs/ScrollerListEx.js +32 -84
- package/lib/cjs/TableEx.d.ts +7 -0
- package/lib/cjs/TableEx.js +6 -12
- package/lib/cjs/pages/DataGridPage.js +3 -32
- package/lib/cjs/pages/FixedListPage.js +5 -34
- package/lib/cjs/pages/ListPage.js +1 -29
- package/lib/cjs/pages/ResponsivePage.d.ts +9 -13
- package/lib/cjs/uses/useGridCacheInitLoad.d.ts +2 -0
- package/lib/cjs/uses/useGridCacheInitLoad.js +41 -0
- package/lib/cjs/uses/useListCacheInitLoad.d.ts +2 -0
- package/lib/cjs/uses/useListCacheInitLoad.js +38 -0
- package/lib/mjs/DataGridEx.d.ts +8 -1
- package/lib/mjs/DataGridEx.js +71 -56
- package/lib/mjs/DataGridRenderers.d.ts +1 -1
- package/lib/mjs/DataGridRenderers.js +1 -1
- package/lib/mjs/MUUtils.d.ts +0 -9
- package/lib/mjs/MUUtils.js +0 -26
- package/lib/mjs/MobileListItemRenderer.d.ts +2 -2
- package/lib/mjs/MobileListItemRenderer.js +3 -4
- package/lib/mjs/ResponsibleContainer.d.ts +9 -13
- package/lib/mjs/ResponsibleContainer.js +19 -58
- package/lib/mjs/ScrollerListEx.d.ts +23 -23
- package/lib/mjs/ScrollerListEx.js +32 -84
- package/lib/mjs/TableEx.d.ts +7 -0
- package/lib/mjs/TableEx.js +6 -12
- package/lib/mjs/pages/DataGridPage.js +3 -32
- package/lib/mjs/pages/FixedListPage.js +5 -34
- package/lib/mjs/pages/ListPage.js +1 -29
- package/lib/mjs/pages/ResponsivePage.d.ts +9 -13
- package/lib/mjs/uses/useGridCacheInitLoad.d.ts +2 -0
- package/lib/mjs/uses/useGridCacheInitLoad.js +35 -0
- package/lib/mjs/uses/useListCacheInitLoad.d.ts +2 -0
- package/lib/mjs/uses/useListCacheInitLoad.js +32 -0
- package/package.json +18 -19
- package/src/DataGridEx.tsx +155 -109
- package/src/DataGridRenderers.tsx +2 -1
- package/src/MUUtils.ts +0 -33
- package/src/MobileListItemRenderer.tsx +4 -4
- package/src/ResponsibleContainer.tsx +50 -111
- package/src/ScrollerListEx.tsx +141 -229
- package/src/TableEx.tsx +20 -12
- package/src/pages/DataGridPage.tsx +3 -49
- package/src/pages/FixedListPage.tsx +5 -49
- package/src/pages/ListPage.tsx +0 -43
- package/src/pages/ResponsivePage.tsx +16 -21
- package/src/uses/useGridCacheInitLoad.ts +55 -0
- package/src/uses/useListCacheInitLoad.ts +51 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { AddressUtils, Culture } from "@etsoo/appscript";
|
|
2
2
|
import { ReactApp } from "../src";
|
|
3
3
|
import { DataTypes, DomUtils, IActionResult, Utils } from "@etsoo/shared";
|
|
4
|
-
import
|
|
4
|
+
import { act } from "react";
|
|
5
5
|
import { createRoot } from "react-dom/client";
|
|
6
|
+
import { screen, waitFor } from "@testing-library/react";
|
|
6
7
|
|
|
7
8
|
// Detected country or region
|
|
8
9
|
const { detectedCountry } = DomUtils;
|
|
@@ -77,7 +78,7 @@ act(() => {
|
|
|
77
78
|
reactRoot.render(<Provider />);
|
|
78
79
|
});
|
|
79
80
|
|
|
80
|
-
test("Test for properties", () => {
|
|
81
|
+
test("Test for properties", async () => {
|
|
81
82
|
const result: IActionResult = {
|
|
82
83
|
ok: false,
|
|
83
84
|
type: "https://tools.ietf.org/html/rfc9110#section-15.5.1",
|
|
@@ -96,10 +97,13 @@ test("Test for properties", () => {
|
|
|
96
97
|
app.alertResult(result);
|
|
97
98
|
});
|
|
98
99
|
|
|
99
|
-
|
|
100
|
+
await waitFor(() => {
|
|
101
|
+
const item = screen.getByText(result.title!);
|
|
102
|
+
expect(item.classList.contains("MuiDialogContent-root")).toBeTruthy();
|
|
103
|
+
});
|
|
100
104
|
});
|
|
101
105
|
|
|
102
|
-
test("Test for alertResult", () => {
|
|
106
|
+
test("Test for alertResult", async () => {
|
|
103
107
|
const result: IActionResult = {
|
|
104
108
|
ok: false,
|
|
105
109
|
type: "TokenExpired",
|
|
@@ -111,7 +115,8 @@ test("Test for alertResult", () => {
|
|
|
111
115
|
app.alertResult(result);
|
|
112
116
|
});
|
|
113
117
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
118
|
+
await waitFor(() => {
|
|
119
|
+
const item = screen.getByText("(TokenExpired)");
|
|
120
|
+
expect(item.nodeName).toBe("SPAN");
|
|
121
|
+
});
|
|
117
122
|
});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { act, render } from "@testing-library/react";
|
|
1
|
+
import { act, render, renderHook } from "@testing-library/react";
|
|
2
2
|
import {
|
|
3
|
-
MUGlobal,
|
|
4
3
|
MobileListItemRenderer,
|
|
5
4
|
ReactAppContext,
|
|
6
5
|
ResponsivePage,
|
|
7
6
|
SearchField
|
|
8
7
|
} from "../src";
|
|
9
8
|
import React from "react";
|
|
9
|
+
import { GridMethodRef } from "@etsoo/react";
|
|
10
10
|
|
|
11
11
|
globalThis.ResizeObserver = vi.fn().mockImplementation(() => ({
|
|
12
12
|
observe: vi.fn(),
|
|
@@ -32,15 +32,21 @@ const fieldTemplate = {
|
|
|
32
32
|
name: "string"
|
|
33
33
|
} as const;
|
|
34
34
|
|
|
35
|
-
it("Render
|
|
35
|
+
it("Render ResponsivePage", async () => {
|
|
36
36
|
act(() => {
|
|
37
|
+
// Hook
|
|
38
|
+
const { result: ref } = renderHook(() =>
|
|
39
|
+
React.useRef<GridMethodRef<Data>>(undefined)
|
|
40
|
+
);
|
|
41
|
+
|
|
37
42
|
// Act
|
|
38
43
|
render(
|
|
39
44
|
<ReactAppContext.Provider value={null}>
|
|
40
45
|
<ResponsivePage<Data, typeof fieldTemplate>
|
|
41
46
|
fields={[<SearchField label="Keyword" name="keyword" minChars={2} />]}
|
|
42
47
|
height={200}
|
|
43
|
-
|
|
48
|
+
rowHeight={[53, 116]}
|
|
49
|
+
mRef={ref.current}
|
|
44
50
|
fieldTemplate={fieldTemplate}
|
|
45
51
|
loadData={({ id }) =>
|
|
46
52
|
Promise.resolve([
|
|
@@ -58,7 +64,7 @@ it("Render ResponsePage", async () => {
|
|
|
58
64
|
valueFormatter: ({ data }) => data?.deviceName ?? data?.name
|
|
59
65
|
}
|
|
60
66
|
]}
|
|
61
|
-
|
|
67
|
+
itemRenderer={(props) =>
|
|
62
68
|
MobileListItemRenderer(props, (data) => {
|
|
63
69
|
return [
|
|
64
70
|
data.name,
|
package/__tests__/SelectEx.tsx
CHANGED
package/lib/cjs/DataGridEx.d.ts
CHANGED
|
@@ -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>, "
|
|
17
|
+
export type DataGridExProps<T extends object, P extends GridJsonData = GridLoadDataProps> = Omit<ScrollerGridProps<T, P>, "cellComponent" | "columnCount" | "columnWidth" | "onClick" | "onDoubleClick" | "onInitLoad" | "rowHeight" | "width"> & Partial<Pick<ScrollerGridProps<T, P>, "rowHeight">> & {
|
|
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
|
package/lib/cjs/DataGridEx.js
CHANGED
|
@@ -16,6 +16,8 @@ const Box_1 = __importDefault(require("@mui/material/Box"));
|
|
|
16
16
|
const TableSortLabel_1 = __importDefault(require("@mui/material/TableSortLabel"));
|
|
17
17
|
const Checkbox_1 = __importDefault(require("@mui/material/Checkbox"));
|
|
18
18
|
const Paper_1 = __importDefault(require("@mui/material/Paper"));
|
|
19
|
+
const GridUtils_1 = require("./GridUtils");
|
|
20
|
+
const useGridCacheInitLoad_1 = require("./uses/useGridCacheInitLoad");
|
|
19
21
|
// Borders
|
|
20
22
|
const boldBorder = "2px solid rgba(224, 224, 224, 1)";
|
|
21
23
|
const thinBorder = "1px solid rgba(224, 224, 224, 1)";
|
|
@@ -135,7 +137,7 @@ function DataGridEx(props) {
|
|
|
135
137
|
}) }));
|
|
136
138
|
}
|
|
137
139
|
// Destruct
|
|
138
|
-
const { alternatingColors = [theme.palette.grey[100], undefined], borderRowsCount, bottomHeight = 53, checkable = false, className, columns, defaultOrderBy, height, headerHeight = 56, headerRenderer = defaultHeaderRenderer, footerRenderer = defaultFooterRenderer, footerItemRenderer = DataGridRenderers_1.DataGridRenderers.defaultFooterItemRenderer, hideFooter = false, hoverColor = "#f6f9fb", idField = "id", mRef = react_2.default.createRef(), onClick, onDoubleClick, selectable = true, selectedColor = "#edf4fb", width, ...rest } = props;
|
|
140
|
+
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_1.DataGridRenderers.defaultFooterItemRenderer, hideFooter = false, hoverColor = "#f6f9fb", idField = "id", mRef = react_2.default.createRef(), onClick, onDataChange, onDoubleClick, onUpdateRows, rowHeight = 53, selectable = true, selectedColor = "#edf4fb", width, ...rest } = props;
|
|
139
141
|
if (checkable) {
|
|
140
142
|
const cbColumn = {
|
|
141
143
|
field: "selected", // Avoid validation from data model
|
|
@@ -168,6 +170,8 @@ function DataGridEx(props) {
|
|
|
168
170
|
columns.unshift(cbColumn);
|
|
169
171
|
}
|
|
170
172
|
}
|
|
173
|
+
// Init handler
|
|
174
|
+
const initHandler = (0, useGridCacheInitLoad_1.useGridCacheInitLoad)(cacheKey, cacheMinutes);
|
|
171
175
|
const refs = react_2.default.useRef({});
|
|
172
176
|
const mRefLocal = (0, react_1.useCombinedRefs)(mRef, (ref) => {
|
|
173
177
|
if (ref == null)
|
|
@@ -226,57 +230,6 @@ function DataGridEx(props) {
|
|
|
226
230
|
div.classList.remove("DataGridEx-Hover");
|
|
227
231
|
});
|
|
228
232
|
};
|
|
229
|
-
/**
|
|
230
|
-
* Item renderer
|
|
231
|
-
*/
|
|
232
|
-
const itemRenderer = ({ columnIndex, rowIndex, style, data, selectedItems, setItems }) => {
|
|
233
|
-
// Column
|
|
234
|
-
const { align, cellRenderer = DataGridRenderers_1.DataGridRenderers.defaultCellRenderer, cellBoxStyle, field, type, valueFormatter, renderProps } = columns[columnIndex];
|
|
235
|
-
// Props
|
|
236
|
-
const formatProps = {
|
|
237
|
-
data,
|
|
238
|
-
field,
|
|
239
|
-
rowIndex,
|
|
240
|
-
columnIndex
|
|
241
|
-
};
|
|
242
|
-
let rowClass = `DataGridEx-Cell${rowIndex % 2}`;
|
|
243
|
-
if (borderRowsCount != null &&
|
|
244
|
-
borderRowsCount > 0 &&
|
|
245
|
-
(rowIndex + 1) % borderRowsCount === 0) {
|
|
246
|
-
rowClass += ` DataGridEx-Cell-Border`;
|
|
247
|
-
}
|
|
248
|
-
// Selected
|
|
249
|
-
const selected = data != null &&
|
|
250
|
-
(selectedRowIndex.current === rowIndex ||
|
|
251
|
-
selectedItems.some((selectedItem) => selectedItem != null && selectedItem[idField] === data[idField]));
|
|
252
|
-
if (selected) {
|
|
253
|
-
rowClass += ` DataGridEx-Selected`;
|
|
254
|
-
}
|
|
255
|
-
// Box style
|
|
256
|
-
const boxStyle = data == null || cellBoxStyle == null
|
|
257
|
-
? undefined
|
|
258
|
-
: typeof cellBoxStyle === "function"
|
|
259
|
-
? cellBoxStyle(data)
|
|
260
|
-
: cellBoxStyle;
|
|
261
|
-
const cellProps = {
|
|
262
|
-
className: "DataGridEx-Cell",
|
|
263
|
-
textAlign: (0, react_1.GridAlignGet)(align, type),
|
|
264
|
-
sx: { ...boxStyle }
|
|
265
|
-
};
|
|
266
|
-
const child = cellRenderer({
|
|
267
|
-
data,
|
|
268
|
-
field,
|
|
269
|
-
formattedValue: valueFormatter ? valueFormatter(formatProps) : undefined,
|
|
270
|
-
selected,
|
|
271
|
-
type,
|
|
272
|
-
rowIndex,
|
|
273
|
-
columnIndex,
|
|
274
|
-
cellProps,
|
|
275
|
-
renderProps: typeof renderProps === "function" ? renderProps(data) : renderProps,
|
|
276
|
-
setItems
|
|
277
|
-
});
|
|
278
|
-
return ((0, jsx_runtime_1.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: (0, jsx_runtime_1.jsx)(Box_1.default, { ...cellProps, onMouseEnter: handleMouseEnter, children: child }) }));
|
|
279
|
-
};
|
|
280
233
|
// Column width calculator
|
|
281
234
|
const widthCalculator = react_2.default.useMemo(() => DataGridExCalColumns(columns), [columns]);
|
|
282
235
|
// Column width
|
|
@@ -294,12 +247,74 @@ function DataGridEx(props) {
|
|
|
294
247
|
const sharedWidth = leftWidth > 0 ? leftWidth / widthCalculator.unset : 0;
|
|
295
248
|
return (column.minWidth || minWidth) + sharedWidth;
|
|
296
249
|
}, [columns, width]);
|
|
250
|
+
const onUpdateRowsHandler = react_2.default.useCallback((rows, state) => {
|
|
251
|
+
GridUtils_1.GridUtils.getUpdateRowsHandler(cacheKey)?.(rows, state);
|
|
252
|
+
onUpdateRows?.(rows, state);
|
|
253
|
+
}, [onUpdateRows, cacheKey]);
|
|
297
254
|
// Table
|
|
298
255
|
const table = react_2.default.useMemo(() => {
|
|
299
|
-
return ((0, jsx_runtime_1.jsx)(react_1.ScrollerGrid, { className: shared_1.Utils.mergeClasses("DataGridEx-Body", "DataGridEx-CustomBar", className, createGridStyle(alternatingColors, selectedColor, hoverColor)),
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
256
|
+
return ((0, jsx_runtime_1.jsx)(react_1.ScrollerGrid, { className: shared_1.Utils.mergeClasses("DataGridEx-Body", "DataGridEx-CustomBar", className, createGridStyle(alternatingColors, selectedColor, hoverColor)), onCellsRendered: cacheKey
|
|
257
|
+
? (visibleCells) => sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(visibleCells))
|
|
258
|
+
: undefined, onInitLoad: initHandler, onUpdateRows: onUpdateRowsHandler, cellComponent: ({ rowIndex, columnIndex, style, rows, states }) => {
|
|
259
|
+
// Column
|
|
260
|
+
const { align, cellRenderer = DataGridRenderers_1.DataGridRenderers.defaultCellRenderer, cellBoxStyle, field, type, valueFormatter, renderProps } = columns[columnIndex];
|
|
261
|
+
// Data
|
|
262
|
+
const data = rows[rowIndex];
|
|
263
|
+
// Props
|
|
264
|
+
const formatProps = {
|
|
265
|
+
data,
|
|
266
|
+
field,
|
|
267
|
+
rowIndex,
|
|
268
|
+
columnIndex
|
|
269
|
+
};
|
|
270
|
+
let rowClass = `DataGridEx-Cell${rowIndex % 2}`;
|
|
271
|
+
if (borderRowsCount != null &&
|
|
272
|
+
borderRowsCount > 0 &&
|
|
273
|
+
(rowIndex + 1) % borderRowsCount === 0) {
|
|
274
|
+
rowClass += ` DataGridEx-Cell-Border`;
|
|
275
|
+
}
|
|
276
|
+
// Selected
|
|
277
|
+
const selected = data != null &&
|
|
278
|
+
(selectedRowIndex.current === rowIndex ||
|
|
279
|
+
states.selectedItems.some((selectedItem) => selectedItem != null &&
|
|
280
|
+
selectedItem[idField] === data[idField]));
|
|
281
|
+
if (selected) {
|
|
282
|
+
rowClass += ` DataGridEx-Selected`;
|
|
283
|
+
}
|
|
284
|
+
// Box style
|
|
285
|
+
const boxStyle = data == null || cellBoxStyle == null
|
|
286
|
+
? undefined
|
|
287
|
+
: typeof cellBoxStyle === "function"
|
|
288
|
+
? cellBoxStyle(data)
|
|
289
|
+
: cellBoxStyle;
|
|
290
|
+
const cellProps = {
|
|
291
|
+
className: "DataGridEx-Cell",
|
|
292
|
+
textAlign: (0, react_1.GridAlignGet)(align, type),
|
|
293
|
+
sx: { ...boxStyle }
|
|
294
|
+
};
|
|
295
|
+
const child = cellRenderer({
|
|
296
|
+
data,
|
|
297
|
+
field,
|
|
298
|
+
formattedValue: valueFormatter
|
|
299
|
+
? valueFormatter(formatProps)
|
|
300
|
+
: undefined,
|
|
301
|
+
selected,
|
|
302
|
+
type,
|
|
303
|
+
rowIndex,
|
|
304
|
+
columnIndex,
|
|
305
|
+
cellProps,
|
|
306
|
+
renderProps: typeof renderProps === "function"
|
|
307
|
+
? renderProps(data)
|
|
308
|
+
: renderProps,
|
|
309
|
+
triggerChange: () => onDataChange?.(rows, rowIndex, columnIndex)
|
|
310
|
+
});
|
|
311
|
+
return ((0, jsx_runtime_1.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: (0, jsx_runtime_1.jsx)(Box_1.default, { ...cellProps, onMouseEnter: handleMouseEnter, children: child }) }));
|
|
312
|
+
}, columnCount: columns.length, columnWidth: columnWidth, defaultOrderBy: defaultOrderBy, height: typeof height === "number"
|
|
313
|
+
? height -
|
|
314
|
+
headerHeight -
|
|
315
|
+
(hideFooter ? 0 : bottomHeight + 1) -
|
|
316
|
+
scrollbarSize
|
|
317
|
+
: height, headerRenderer: headerRenderer, idField: idField, footerRenderer: hideFooter ? undefined : footerRenderer, rowHeight: rowHeight, width: Math.max(width ?? 0, widthCalculator.total), mRef: mRefLocal, ...rest }));
|
|
303
318
|
}, [width]);
|
|
304
319
|
return ((0, jsx_runtime_1.jsx)(Paper_1.default, { sx: {
|
|
305
320
|
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
|
|
@@ -21,7 +21,7 @@ var DataGridRenderers;
|
|
|
21
21
|
* @param param Props
|
|
22
22
|
* @returns Component
|
|
23
23
|
*/
|
|
24
|
-
function defaultCellRenderer({ cellProps, data, field, formattedValue, columnIndex, type, renderProps }) {
|
|
24
|
+
function defaultCellRenderer({ cellProps, data, field, formattedValue, columnIndex, type, renderProps, triggerChange }) {
|
|
25
25
|
// Is loading
|
|
26
26
|
if (data == null) {
|
|
27
27
|
// First column, show loading indicator
|
package/lib/cjs/MUUtils.d.ts
CHANGED
|
@@ -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
|
}
|
package/lib/cjs/MUUtils.js
CHANGED
|
@@ -29,30 +29,4 @@ var MUUtils;
|
|
|
29
29
|
return items;
|
|
30
30
|
}
|
|
31
31
|
MUUtils.getGridData = getGridData;
|
|
32
|
-
/**
|
|
33
|
-
* Setup paging keysets
|
|
34
|
-
* @param data Paging data
|
|
35
|
-
* @param lastItem Last item of the query
|
|
36
|
-
* @param idField Id field
|
|
37
|
-
*/
|
|
38
|
-
function setupPagingKeysets(data, lastItem, idField) {
|
|
39
|
-
// If the id field is not set for ordering, add it with descending
|
|
40
|
-
if (typeof data.queryPaging === "object") {
|
|
41
|
-
const orderBy = (data.queryPaging.orderBy ??= []);
|
|
42
|
-
const idUpper = idField.toUpperCase();
|
|
43
|
-
if (!orderBy.find((o) => o.field.toUpperCase() === idUpper)) {
|
|
44
|
-
orderBy.push({ field: idField, desc: true, unique: true });
|
|
45
|
-
}
|
|
46
|
-
// Set the paging keysets
|
|
47
|
-
if (lastItem) {
|
|
48
|
-
const keysets = orderBy.map((o) => Reflect.get(lastItem, o.field));
|
|
49
|
-
data.queryPaging.keysets = keysets;
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
data.queryPaging.keysets = undefined;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return data;
|
|
56
|
-
}
|
|
57
|
-
MUUtils.setupPagingKeysets = setupPagingKeysets;
|
|
58
32
|
})(MUUtils || (exports.MUUtils = MUUtils = {}));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ListItemReact } from "@etsoo/react";
|
|
2
2
|
import React from "react";
|
|
3
|
-
import {
|
|
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,
|
|
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)[],
|
|
@@ -17,16 +17,15 @@ const CardContent_1 = __importDefault(require("@mui/material/CardContent"));
|
|
|
17
17
|
* @param renderer Renderer for card content
|
|
18
18
|
* @returns Component
|
|
19
19
|
*/
|
|
20
|
-
function MobileListItemRenderer({ data,
|
|
20
|
+
function MobileListItemRenderer({ data, margins, style }, renderer) {
|
|
21
21
|
// Loading
|
|
22
22
|
if (data == null)
|
|
23
23
|
return (0, jsx_runtime_1.jsx)(LinearProgress_1.default, {});
|
|
24
24
|
// Elements
|
|
25
25
|
const [title, subheader, actions, children, cardActions] = renderer(data);
|
|
26
26
|
return ((0, jsx_runtime_1.jsxs)(Card_1.default, { sx: {
|
|
27
|
-
height: itemHeight,
|
|
28
27
|
...margins
|
|
29
|
-
}, children: [(0, jsx_runtime_1.jsx)(CardHeader_1.default, { sx: { paddingBottom: 0.5 }, action: Array.isArray(actions) ? ((0, jsx_runtime_1.jsx)(MoreFab_1.MoreFab, { iconButton: true, size: "small", anchorOrigin: {
|
|
28
|
+
}, style: style, children: [(0, jsx_runtime_1.jsx)(CardHeader_1.default, { sx: { paddingBottom: 0.5 }, action: Array.isArray(actions) ? ((0, jsx_runtime_1.jsx)(MoreFab_1.MoreFab, { iconButton: true, size: "small", anchorOrigin: {
|
|
30
29
|
vertical: "bottom",
|
|
31
30
|
horizontal: "right"
|
|
32
31
|
}, transformOrigin: {
|
|
@@ -37,6 +36,6 @@ function MobileListItemRenderer({ data, itemHeight, margins }, renderer) {
|
|
|
37
36
|
subheader: { variant: "caption" }
|
|
38
37
|
} }), (0, jsx_runtime_1.jsx)(CardContent_1.default, { sx: {
|
|
39
38
|
paddingTop: 0,
|
|
40
|
-
paddingBottom: cardActions == null ? Reflect.get(margins, "marginBottom") : 0
|
|
39
|
+
paddingBottom: cardActions == null ? Reflect.get(margins, "marginBottom") ?? 0 : 0
|
|
41
40
|
}, children: children }), cardActions] }));
|
|
42
41
|
}
|
|
@@ -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 {
|
|
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" | "
|
|
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?:
|
|
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.
|
|
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
|
*/
|
|
@@ -32,7 +32,7 @@ function defaultContainerBoxSx(paddings, hasField, _dataGrid) {
|
|
|
32
32
|
*/
|
|
33
33
|
function ResponsibleContainer(props) {
|
|
34
34
|
// Destruct
|
|
35
|
-
const { adjustHeight, adjustFabHeight, cacheKey, cacheMinutes = 15, columns, containerBoxSx = defaultContainerBoxSx, elementReady, fields, fieldTemplate, height, loadData, mRef, paddings = MUGlobal_1.MUGlobal.pagePaddings, pullToRefresh = true, quickAction, sizeReadyMiliseconds = 0, searchBarHeight = 45.6, searchBarBottom = 8, searchBarTop, ...rest } = props;
|
|
35
|
+
const { adjustHeight, adjustFabHeight, cacheKey, cacheMinutes = 15, columns, containerBoxSx = defaultContainerBoxSx, elementReady, fields, fieldTemplate, height, loadData, mRef, paddings = MUGlobal_1.MUGlobal.pagePaddings, pullToRefresh = true, quickAction, rowHeight, sizeReadyMiliseconds = 0, searchBarHeight = 45.6, searchBarBottom = 8, searchBarTop, ...rest } = props;
|
|
36
36
|
// Labels
|
|
37
37
|
const labels = Labels_1.Labels.CommonPage;
|
|
38
38
|
// Refs
|
|
@@ -42,6 +42,8 @@ function ResponsibleContainer(props) {
|
|
|
42
42
|
if (ref == null)
|
|
43
43
|
return;
|
|
44
44
|
state.ref = ref;
|
|
45
|
+
if (ref.element && elementReady)
|
|
46
|
+
elementReady(ref.element, true);
|
|
45
47
|
});
|
|
46
48
|
// Screen size detection
|
|
47
49
|
const showDataGrid = (0, useMediaQuery_1.default)("(min-width:600px)");
|
|
@@ -58,6 +60,16 @@ function ResponsibleContainer(props) {
|
|
|
58
60
|
state.mounted = true;
|
|
59
61
|
return loadData(GridUtils_1.GridUtils.createLoader(props, fieldTemplate, cacheKey, false), lastItem);
|
|
60
62
|
};
|
|
63
|
+
const getRowHeight = react_1.default.useCallback((isGrid) => {
|
|
64
|
+
if (rowHeight == null)
|
|
65
|
+
return undefined;
|
|
66
|
+
else if (typeof rowHeight === "number")
|
|
67
|
+
return isGrid ? undefined : rowHeight;
|
|
68
|
+
else if (Array.isArray(rowHeight))
|
|
69
|
+
return rowHeight[isGrid ? 0 : 1];
|
|
70
|
+
else
|
|
71
|
+
return rowHeight(isGrid);
|
|
72
|
+
}, [rowHeight]);
|
|
61
73
|
// Search data
|
|
62
74
|
const searchData = (0, react_2.useSearchParamsWithCache)(cacheKey);
|
|
63
75
|
// On submit callback
|
|
@@ -83,44 +95,6 @@ function ResponsibleContainer(props) {
|
|
|
83
95
|
state.rect = rect;
|
|
84
96
|
return false;
|
|
85
97
|
});
|
|
86
|
-
const onInitLoad = (ref) => {
|
|
87
|
-
// Avoid repeatedly load from cache
|
|
88
|
-
if (refs.current.initLoaded || !cacheKey)
|
|
89
|
-
return undefined;
|
|
90
|
-
// Cache data
|
|
91
|
-
const cacheData = GridUtils_1.GridUtils.getCacheData(cacheKey, cacheMinutes);
|
|
92
|
-
if (cacheData) {
|
|
93
|
-
const { rows, state } = cacheData;
|
|
94
|
-
GridUtils_1.GridUtils.mergeSearchData(state, searchData);
|
|
95
|
-
// Scroll position
|
|
96
|
-
const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
|
|
97
|
-
if (scrollData) {
|
|
98
|
-
if ("resetAfterColumnIndex" in ref) {
|
|
99
|
-
const { scrollLeft, scrollTop } = JSON.parse(scrollData);
|
|
100
|
-
globalThis.setTimeout(() => ref.scrollTo({ scrollLeft, scrollTop }), 0);
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
const { scrollOffset } = JSON.parse(scrollData);
|
|
104
|
-
globalThis.setTimeout(() => ref.scrollTo(scrollOffset), 0);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
// Update flag value
|
|
108
|
-
refs.current.initLoaded = true;
|
|
109
|
-
// Return cached rows and state
|
|
110
|
-
return [rows, state];
|
|
111
|
-
}
|
|
112
|
-
return undefined;
|
|
113
|
-
};
|
|
114
|
-
const onListScroll = (props) => {
|
|
115
|
-
if (!cacheKey || !refs.current.initLoaded)
|
|
116
|
-
return;
|
|
117
|
-
sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
|
|
118
|
-
};
|
|
119
|
-
const onGridScroll = (props) => {
|
|
120
|
-
if (!cacheKey || !refs.current.initLoaded)
|
|
121
|
-
return;
|
|
122
|
-
sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
|
|
123
|
-
};
|
|
124
98
|
// Rect
|
|
125
99
|
const rect = dimensions[0][2];
|
|
126
100
|
// Create list
|
|
@@ -150,26 +124,13 @@ function ResponsibleContainer(props) {
|
|
|
150
124
|
if (adjustFabHeight)
|
|
151
125
|
heightLocal = adjustFabHeight(heightLocal, showDataGrid);
|
|
152
126
|
if (showDataGrid) {
|
|
153
|
-
//
|
|
154
|
-
|
|
155
|
-
return ((0, jsx_runtime_1.jsx)(Box_1.default, { className: "DataGridBox", children: (0, jsx_runtime_1.jsx)(DataGridEx_1.DataGridEx, { autoLoad: !hasFields, height: heightLocal, width: rect.width, loadData: localLoadData, mRef: mRefs, onDoubleClick: (_, data) => quickAction && quickAction(data),
|
|
156
|
-
if (element != null && elementReady)
|
|
157
|
-
elementReady(element, true);
|
|
158
|
-
}, onScroll: onGridScroll, columns: columns, onUpdateRows: GridUtils_1.GridUtils.getUpdateRowsHandler(cacheKey), onInitLoad: onInitLoad, ...rest }) }));
|
|
127
|
+
// Remove useless props
|
|
128
|
+
const { itemRenderer, ...gridProps } = rest;
|
|
129
|
+
return ((0, jsx_runtime_1.jsx)(Box_1.default, { className: "DataGridBox", children: (0, jsx_runtime_1.jsx)(DataGridEx_1.DataGridEx, { autoLoad: !hasFields, height: heightLocal, width: rect.width, loadData: localLoadData, mRef: mRefs, onDoubleClick: (_, data) => quickAction && quickAction(data), columns: columns, rowHeight: getRowHeight(true), ...gridProps }) }));
|
|
159
130
|
}
|
|
160
|
-
//
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
delete rest.bottomHeight;
|
|
164
|
-
delete rest.footerItemRenderer;
|
|
165
|
-
delete rest.headerHeight;
|
|
166
|
-
delete rest.hideFooter;
|
|
167
|
-
delete rest.hoverColor;
|
|
168
|
-
delete rest.selectable;
|
|
169
|
-
return ((0, jsx_runtime_1.jsx)(Box_1.default, { className: "ListBox", sx: { height: heightLocal }, children: (0, jsx_runtime_1.jsx)(ScrollerListEx_1.ScrollerListEx, { autoLoad: !hasFields, height: heightLocal, loadData: localLoadData, onUpdateRows: GridUtils_1.GridUtils.getUpdateRowsHandler(cacheKey), onInitLoad: onInitLoad, mRef: mRefs, onClick: (event, data) => quickAction && react_2.ReactUtils.isSafeClick(event) && quickAction(data), oRef: (element) => {
|
|
170
|
-
if (element != null && elementReady)
|
|
171
|
-
elementReady(element, false);
|
|
172
|
-
}, onScroll: onListScroll, ...rest }) }));
|
|
131
|
+
// Remove useless props
|
|
132
|
+
const { checkable, borderRowsCount, bottomHeight, footerItemRenderer, headerHeight, hideFooter, hoverColor, selectable, onCellsRendered, ...listProps } = rest;
|
|
133
|
+
return ((0, jsx_runtime_1.jsx)(Box_1.default, { className: "ListBox", sx: { height: heightLocal }, children: (0, jsx_runtime_1.jsx)(ScrollerListEx_1.ScrollerListEx, { autoLoad: !hasFields, height: heightLocal, loadData: localLoadData, mRef: mRefs, onClick: (event, data) => quickAction && react_2.ReactUtils.isSafeClick(event) && quickAction(data), rowHeight: getRowHeight(false), ...listProps }) }));
|
|
173
134
|
})();
|
|
174
135
|
const searchBar = react_1.default.useMemo(() => {
|
|
175
136
|
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
|
|
7
|
+
export type ScrollerListExItemRendererProps<T> = {
|
|
9
8
|
/**
|
|
10
|
-
*
|
|
9
|
+
* Row index
|
|
11
10
|
*/
|
|
12
|
-
|
|
11
|
+
index: number;
|
|
13
12
|
/**
|
|
14
|
-
*
|
|
13
|
+
* Row data
|
|
15
14
|
*/
|
|
16
|
-
|
|
15
|
+
data: T;
|
|
17
16
|
/**
|
|
18
|
-
*
|
|
17
|
+
* Style
|
|
19
18
|
*/
|
|
20
|
-
|
|
19
|
+
style: React.CSSProperties;
|
|
21
20
|
/**
|
|
22
21
|
* Default margins
|
|
23
22
|
*/
|
|
24
23
|
margins: object;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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>, "
|
|
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
|
-
*
|
|
38
|
+
* Cache key
|
|
43
39
|
*/
|
|
44
|
-
|
|
40
|
+
cacheKey?: string;
|
|
45
41
|
/**
|
|
46
|
-
*
|
|
42
|
+
* Cache minutes
|
|
47
43
|
*/
|
|
48
|
-
|
|
44
|
+
cacheMinutes?: number;
|
|
49
45
|
/**
|
|
50
|
-
*
|
|
46
|
+
* Cell margins, default to half of MUGlobal.pagePaddings
|
|
47
|
+
*/
|
|
48
|
+
cellMargins?: object;
|
|
49
|
+
/**
|
|
50
|
+
* Item renderer
|
|
51
51
|
*/
|
|
52
|
-
|
|
52
|
+
itemRenderer?: (props: ScrollerListExItemRendererProps<T>) => React.ReactNode;
|
|
53
53
|
/**
|
|
54
54
|
* Double click handler
|
|
55
55
|
*/
|