@etsoo/materialui 1.5.70 → 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 (95) hide show
  1. package/__tests__/ReactAppTests.tsx +12 -7
  2. package/__tests__/SelectEx.tsx +1 -1
  3. package/__tests__/tsconfig.json +1 -1
  4. package/lib/cjs/ButtonPopupCheckbox.js +1 -1
  5. package/lib/cjs/ButtonPopupRadio.js +1 -1
  6. package/lib/cjs/DataGridEx.d.ts +8 -1
  7. package/lib/cjs/DataGridEx.js +71 -56
  8. package/lib/cjs/DataGridRenderers.d.ts +1 -1
  9. package/lib/cjs/DataGridRenderers.js +1 -1
  10. package/lib/cjs/DnDList.js +1 -1
  11. package/lib/cjs/MUUtils.d.ts +0 -9
  12. package/lib/cjs/MUUtils.js +0 -26
  13. package/lib/cjs/MobileListItemRenderer.d.ts +2 -2
  14. package/lib/cjs/ResponsibleContainer.d.ts +2 -7
  15. package/lib/cjs/ResponsibleContainer.js +8 -57
  16. package/lib/cjs/ScrollerListEx.d.ts +24 -9
  17. package/lib/cjs/ScrollerListEx.js +36 -39
  18. package/lib/cjs/SelectEx.js +2 -2
  19. package/lib/cjs/TableEx.d.ts +7 -0
  20. package/lib/cjs/TableEx.js +6 -12
  21. package/lib/cjs/app/ReactApp.d.ts +1 -3
  22. package/lib/cjs/custom/FieldDateInput.js +1 -1
  23. package/lib/cjs/custom/FieldInput.js +1 -1
  24. package/lib/cjs/custom/FieldJson.js +1 -1
  25. package/lib/cjs/custom/FieldNumberInput.js +1 -1
  26. package/lib/cjs/custom/FieldTexarea.js +1 -1
  27. package/lib/cjs/html/HtmlDiv.d.ts +24 -7
  28. package/lib/cjs/html/HtmlDiv.js +5 -1
  29. package/lib/cjs/pages/DataGridPage.js +3 -32
  30. package/lib/cjs/pages/FixedListPage.js +5 -34
  31. package/lib/cjs/pages/ListPage.js +1 -29
  32. package/lib/cjs/pages/ResponsivePage.d.ts +2 -7
  33. package/lib/cjs/uses/useGridCacheInitLoad.d.ts +2 -0
  34. package/lib/cjs/uses/useGridCacheInitLoad.js +41 -0
  35. package/lib/cjs/uses/useListCacheInitLoad.d.ts +2 -0
  36. package/lib/cjs/uses/useListCacheInitLoad.js +38 -0
  37. package/lib/mjs/ButtonPopupCheckbox.js +1 -1
  38. package/lib/mjs/ButtonPopupRadio.js +1 -1
  39. package/lib/mjs/DataGridEx.d.ts +8 -1
  40. package/lib/mjs/DataGridEx.js +71 -56
  41. package/lib/mjs/DataGridRenderers.d.ts +1 -1
  42. package/lib/mjs/DataGridRenderers.js +1 -1
  43. package/lib/mjs/DnDList.js +1 -1
  44. package/lib/mjs/MUUtils.d.ts +0 -9
  45. package/lib/mjs/MUUtils.js +0 -26
  46. package/lib/mjs/MobileListItemRenderer.d.ts +2 -2
  47. package/lib/mjs/ResponsibleContainer.d.ts +2 -7
  48. package/lib/mjs/ResponsibleContainer.js +8 -57
  49. package/lib/mjs/ScrollerListEx.d.ts +24 -9
  50. package/lib/mjs/ScrollerListEx.js +36 -39
  51. package/lib/mjs/SelectEx.js +2 -2
  52. package/lib/mjs/TableEx.d.ts +7 -0
  53. package/lib/mjs/TableEx.js +6 -12
  54. package/lib/mjs/app/ReactApp.d.ts +1 -3
  55. package/lib/mjs/custom/FieldDateInput.js +1 -1
  56. package/lib/mjs/custom/FieldInput.js +1 -1
  57. package/lib/mjs/custom/FieldJson.js +1 -1
  58. package/lib/mjs/custom/FieldNumberInput.js +1 -1
  59. package/lib/mjs/custom/FieldTexarea.js +1 -1
  60. package/lib/mjs/html/HtmlDiv.d.ts +24 -7
  61. package/lib/mjs/html/HtmlDiv.js +2 -1
  62. package/lib/mjs/pages/DataGridPage.js +3 -32
  63. package/lib/mjs/pages/FixedListPage.js +5 -34
  64. package/lib/mjs/pages/ListPage.js +1 -29
  65. package/lib/mjs/pages/ResponsivePage.d.ts +2 -7
  66. package/lib/mjs/uses/useGridCacheInitLoad.d.ts +2 -0
  67. package/lib/mjs/uses/useGridCacheInitLoad.js +35 -0
  68. package/lib/mjs/uses/useListCacheInitLoad.d.ts +2 -0
  69. package/lib/mjs/uses/useListCacheInitLoad.js +32 -0
  70. package/package.json +18 -19
  71. package/setupTests.ts +2 -0
  72. package/src/ButtonPopupCheckbox.tsx +1 -1
  73. package/src/ButtonPopupRadio.tsx +1 -1
  74. package/src/DataGridEx.tsx +151 -108
  75. package/src/DataGridRenderers.tsx +2 -1
  76. package/src/DnDList.tsx +1 -1
  77. package/src/MUUtils.ts +0 -33
  78. package/src/MobileListItemRenderer.tsx +2 -2
  79. package/src/ResponsibleContainer.tsx +21 -94
  80. package/src/ScrollerListEx.tsx +110 -122
  81. package/src/SelectEx.tsx +2 -2
  82. package/src/TableEx.tsx +20 -12
  83. package/src/custom/CustomFieldUtils.tsx +1 -1
  84. package/src/custom/FieldDateInput.tsx +1 -1
  85. package/src/custom/FieldInput.tsx +1 -1
  86. package/src/custom/FieldJson.tsx +1 -1
  87. package/src/custom/FieldNumberInput.tsx +1 -1
  88. package/src/custom/FieldTexarea.tsx +1 -1
  89. package/src/html/HtmlDiv.tsx +13 -9
  90. package/src/pages/DataGridPage.tsx +3 -49
  91. package/src/pages/FixedListPage.tsx +5 -49
  92. package/src/pages/ListPage.tsx +0 -43
  93. package/src/pages/ResponsivePage.tsx +3 -11
  94. package/src/uses/useGridCacheInitLoad.ts +55 -0
  95. package/src/uses/useListCacheInitLoad.ts +51 -0
@@ -11,6 +11,9 @@ const shared_1 = require("@etsoo/shared");
11
11
  const react_2 = __importDefault(require("react"));
12
12
  const MUGlobal_1 = require("./MUGlobal");
13
13
  const styles_1 = require("@mui/material/styles");
14
+ const GridUtils_1 = require("./GridUtils");
15
+ const useListCacheInitLoad_1 = require("./uses/useListCacheInitLoad");
16
+ const Box_1 = __importDefault(require("@mui/material/Box"));
14
17
  // Scroll bar size
15
18
  const scrollbarSize = 16;
16
19
  // Selected class name
@@ -74,24 +77,6 @@ const defaultMargin = (margin, horizon) => {
74
77
  marginBottom: half
75
78
  };
76
79
  };
77
- // Default itemRenderer
78
- function defaultItemRenderer({ index, innerItemRenderer, data, onMouseDown, selected, style, itemHeight, onClick, onDoubleClick, space, margins }) {
79
- // Child
80
- const child = innerItemRenderer({
81
- index,
82
- data,
83
- style,
84
- selected,
85
- itemHeight,
86
- space,
87
- margins
88
- });
89
- let rowClass = `ScrollerListEx-Row${index % 2}`;
90
- if (selected)
91
- rowClass += ` ${selectedClassName}`;
92
- // Layout
93
- return ((0, jsx_runtime_1.jsx)("div", { className: rowClass, style: style, onMouseDown: (event) => onMouseDown(event.currentTarget, data), onClick: (event) => onClick && onClick(event, data), onDoubleClick: (event) => onDoubleClick && onDoubleClick(event, data), children: child }));
94
- }
95
80
  /**
96
81
  * Extended ScrollerList
97
82
  * @param props Props
@@ -99,7 +84,7 @@ function defaultItemRenderer({ index, innerItemRenderer, data, onMouseDown, sele
99
84
  */
100
85
  function ScrollerListEx(props) {
101
86
  // Selected item ref
102
- const selectedItem = react_2.default.useRef();
87
+ const selectedItem = react_2.default.useRef(null);
103
88
  const onMouseDown = (div, data) => {
104
89
  // Destruct
105
90
  const [selectedDiv, selectedData] = selectedItem.current ?? [];
@@ -119,20 +104,12 @@ function ScrollerListEx(props) {
119
104
  return selected;
120
105
  };
121
106
  // Destruct
122
- const { alternatingColors = [undefined, undefined], className, idField = "id", innerItemRenderer, itemSize, itemRenderer = (itemProps) => {
123
- const [itemHeight, space, margins] = calculateItemSize(itemProps.index);
124
- return defaultItemRenderer({
125
- itemHeight,
126
- innerItemRenderer,
127
- onMouseDown,
128
- onClick,
129
- onDoubleClick,
130
- space,
131
- margins,
132
- selected: isSelected(itemProps.data),
133
- ...itemProps
134
- });
135
- }, onClick, onDoubleClick, onSelectChange, selectedColor = "#edf4fb", ...rest } = props;
107
+ const { alternatingColors = [undefined, undefined], className, cacheKey, cacheMinutes = 15, idField = "id", itemSize, itemRenderer = ({ data, itemHeight, margins }) => ((0, jsx_runtime_1.jsx)(Box_1.default, { component: "pre", sx: {
108
+ height: itemHeight,
109
+ ...margins
110
+ }, children: JSON.stringify(data) })), onClick, onDoubleClick, onUpdateRows, onSelectChange, selectedColor = "#edf4fb", ...rest } = props;
111
+ // Init handler
112
+ const initHandler = (0, useListCacheInitLoad_1.useListCacheInitLoad)(cacheKey, cacheMinutes);
136
113
  // Theme
137
114
  const theme = (0, styles_1.useTheme)();
138
115
  // Cache calculation
@@ -156,11 +133,31 @@ function ScrollerListEx(props) {
156
133
  // Calculation
157
134
  return itemSizeResult;
158
135
  };
159
- // Local item size
160
- const itemSizeLocal = (index) => {
161
- const [size, space] = calculateItemSize(index);
162
- return size + space;
163
- };
136
+ const onUpdateRowsHandler = react_2.default.useCallback((rows, state) => {
137
+ GridUtils_1.GridUtils.getUpdateRowsHandler(cacheKey)?.(rows, state);
138
+ onUpdateRows?.(rows, state);
139
+ }, [onUpdateRows, cacheKey]);
164
140
  // Layout
165
- return ((0, jsx_runtime_1.jsx)(react_1.ScrollerList, { className: shared_1.Utils.mergeClasses("ScrollerListEx-Body", className, createGridStyle(alternatingColors, selectedColor)), idField: idField, itemRenderer: itemRenderer, itemSize: itemSizeLocal, ...rest }));
141
+ return ((0, jsx_runtime_1.jsx)(react_1.ScrollerList, { className: shared_1.Utils.mergeClasses("ScrollerListEx-Body", className, createGridStyle(alternatingColors, selectedColor)), idField: idField, onRowsRendered: cacheKey
142
+ ? (visibleRows) => sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(visibleRows))
143
+ : undefined, onInitLoad: initHandler, onUpdateRows: onUpdateRowsHandler, rowComponent: ({ index, items, style }) => {
144
+ const data = items[index];
145
+ const selected = isSelected(data);
146
+ const rowClass = `ScrollerListEx-Row${index % 2}${selected ? ` ${selectedClassName}` : ""}`;
147
+ const [itemHeight, space, margins] = calculateItemSize(index);
148
+ // Child
149
+ const child = itemRenderer({
150
+ index,
151
+ data,
152
+ style,
153
+ selected,
154
+ itemHeight,
155
+ space,
156
+ margins
157
+ });
158
+ return ((0, jsx_runtime_1.jsx)("div", { className: rowClass, style: style, onMouseDown: (event) => onMouseDown(event.currentTarget, data), onClick: (event) => onClick && onClick(event, data), onDoubleClick: (event) => onDoubleClick && onDoubleClick(event, data), children: child }));
159
+ }, rowHeight: (index) => {
160
+ const [size, space] = calculateItemSize(index);
161
+ return size + space;
162
+ }, ...rest }));
166
163
  }
@@ -69,7 +69,7 @@ function SelectEx(props) {
69
69
  }, [options, propertyWay, setOptionsAdd]);
70
70
  // Value state
71
71
  const [valueState, setValueStateBase] = react_1.default.useState(valueSource);
72
- const valueRef = react_1.default.useRef();
72
+ const valueRef = react_1.default.useRef(null);
73
73
  const setValueState = (newValue) => {
74
74
  valueRef.current = newValue;
75
75
  setValueStateBase(newValue);
@@ -114,7 +114,7 @@ function SelectEx(props) {
114
114
  : option[labelField];
115
115
  };
116
116
  // Refs
117
- const divRef = react_1.default.useRef();
117
+ const divRef = react_1.default.useRef(null);
118
118
  // Refresh list data
119
119
  const refreshData = () => {
120
120
  if (loadData == null)
@@ -43,6 +43,13 @@ export type TableExProps<T extends object, D extends DataTypes.Keys<T>> = TableP
43
43
  * Methods
44
44
  */
45
45
  mRef?: React.Ref<TableExMethodRef<T>>;
46
+ /**
47
+ * Data change handler
48
+ * @param rows Rows
49
+ * @param rowIndex Row index
50
+ * @param columnIndex Column index
51
+ */
52
+ onDataChange?: (rows: T[], rowIndex: number, columnIndex: number) => void;
46
53
  /**
47
54
  * On items select change
48
55
  */
@@ -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));
@@ -173,9 +173,7 @@ export declare class ReactApp<S extends IAppSettings, D extends IUser> extends C
173
173
  * @param props Props
174
174
  */
175
175
  showInputDialog({ title, message, callback, ...rest }: InputDialogProps): INotificationReact;
176
- stateDetector(props: IStateProps): React.FunctionComponentElement<{
177
- children?: React.ReactNode | undefined;
178
- }>;
176
+ stateDetector(props: IStateProps): React.FunctionComponentElement<React.FragmentProps>;
179
177
  /**
180
178
  * User login extended
181
179
  * @param user New user
@@ -16,7 +16,7 @@ const Typography_1 = __importDefault(require("@mui/material/Typography"));
16
16
  */
17
17
  const FieldDateInput = ({ field, mref, onChange, defaultValue }) => {
18
18
  // Ref
19
- const inputRef = react_1.default.useRef();
19
+ const inputRef = react_1.default.useRef(null);
20
20
  const getValue = () => inputRef.current == null
21
21
  ? undefined
22
22
  : shared_1.DateUtils.parse(inputRef.current.value);
@@ -15,7 +15,7 @@ const Typography_1 = __importDefault(require("@mui/material/Typography"));
15
15
  */
16
16
  const FieldInput = ({ field, mref, onChange, defaultValue }) => {
17
17
  // Ref
18
- const inputRef = react_1.default.useRef();
18
+ const inputRef = react_1.default.useRef(null);
19
19
  const getValue = () => inputRef.current?.value;
20
20
  react_1.default.useImperativeHandle(mref, () => ({
21
21
  getValue,
@@ -26,7 +26,7 @@ function parseJson(value) {
26
26
  */
27
27
  const FieldJson = ({ field, mref, onChange, defaultValue }) => {
28
28
  // Ref
29
- const inputRef = react_1.default.useRef();
29
+ const inputRef = react_1.default.useRef(null);
30
30
  const getValue = () => parseJson(inputRef.current?.value);
31
31
  const setValue = (value) => {
32
32
  if (inputRef.current) {
@@ -16,7 +16,7 @@ const Typography_1 = __importDefault(require("@mui/material/Typography"));
16
16
  */
17
17
  const FieldNumberInput = ({ field, mref, onChange, defaultValue }) => {
18
18
  // Ref
19
- const inputRef = react_1.default.useRef();
19
+ const inputRef = react_1.default.useRef(null);
20
20
  const getValue = () => {
21
21
  const value = inputRef.current?.valueAsNumber;
22
22
  return shared_1.NumberUtils.parse(value);
@@ -15,7 +15,7 @@ const Typography_1 = __importDefault(require("@mui/material/Typography"));
15
15
  */
16
16
  const FieldTexarea = ({ field, mref, onChange, defaultValue }) => {
17
17
  // Ref
18
- const inputRef = react_1.default.useRef();
18
+ const inputRef = react_1.default.useRef(null);
19
19
  const getValue = () => inputRef.current?.value;
20
20
  const setValue = (value) => {
21
21
  if (inputRef.current)
@@ -1,4 +1,27 @@
1
1
  import { HTMLAttributes } from "react";
2
+ declare class HtmlDivElement extends HTMLElement {
3
+ static get observedAttributes(): string[];
4
+ private wrapper;
5
+ private observer;
6
+ private _displayStyle?;
7
+ /**
8
+ * Display style
9
+ */
10
+ get displayStyle(): string | undefined;
11
+ set displayStyle(style: string | undefined);
12
+ constructor();
13
+ connectedCallback(): void;
14
+ disconnectedCallback(): void;
15
+ attributeChangedCallback(name: string, _oldValue: any, newValue: any): void;
16
+ setContent(): void;
17
+ }
18
+ declare module "react" {
19
+ namespace JSX {
20
+ interface IntrinsicElements {
21
+ "html-div": React.DetailedHTMLProps<React.HTMLAttributes<HtmlDivElement>, HtmlDivElement>;
22
+ }
23
+ }
24
+ }
2
25
  /**
3
26
  * Custom HTML element properties
4
27
  * 自定义 HTML 元素属性
@@ -10,13 +33,6 @@ export type HtmlDivProps = HTMLAttributes<HTMLElement> & {
10
33
  */
11
34
  displayStyle?: string;
12
35
  };
13
- declare global {
14
- namespace JSX {
15
- interface IntrinsicElements {
16
- "html-div": React.HTMLAttributes<HTMLElement>;
17
- }
18
- }
19
- }
20
36
  /**
21
37
  * Custom HTML element that sanitizes and displays HTML content
22
38
  * 自定义 HTML 元素,用于清理和显示 HTML 内容
@@ -24,3 +40,4 @@ declare global {
24
40
  * @returns Component
25
41
  */
26
42
  export declare function HtmlDiv(props: HtmlDivProps): import("react/jsx-runtime").JSX.Element;
43
+ export {};
@@ -1,8 +1,12 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.HtmlDiv = HtmlDiv;
4
7
  const jsx_runtime_1 = require("react/jsx-runtime");
5
8
  const shared_1 = require("@etsoo/shared");
9
+ const dompurify_1 = __importDefault(require("dompurify"));
6
10
  class HtmlDivElement extends HTMLElement {
7
11
  static get observedAttributes() {
8
12
  return ["displaystyle"];
@@ -86,7 +90,7 @@ class HtmlDivElement extends HTMLElement {
86
90
  wrapper.innerHTML = this.textContent;
87
91
  }
88
92
  else {
89
- wrapper.innerHTML = html;
93
+ wrapper.innerHTML = dompurify_1.default.sanitize(html);
90
94
  }
91
95
  this.textContent = null; // Clear the textContent to avoid duplication
92
96
  }
@@ -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();
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();
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();
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
+ }
@@ -109,7 +109,7 @@ export function ButtonPopupCheckbox(props) {
109
109
  setSelectedIds(value);
110
110
  }, [value]);
111
111
  // Selected ids
112
- const tempSelectedIds = React.useRef();
112
+ const tempSelectedIds = React.useRef(null);
113
113
  // Click handler
114
114
  const clickHandler = () => {
115
115
  app.showInputDialog({
@@ -96,7 +96,7 @@ export function ButtonPopupRadio(props) {
96
96
  setCurrentValue(value);
97
97
  }, [value]);
98
98
  // Selected id
99
- const tempSelectedId = React.useRef();
99
+ const tempSelectedId = React.useRef(null);
100
100
  // Click handler
101
101
  const clickHandler = () => {
102
102
  app.showInputDialog({
@@ -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