@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.
- package/__tests__/ReactAppTests.tsx +12 -7
- package/__tests__/SelectEx.tsx +1 -1
- package/__tests__/tsconfig.json +1 -1
- package/lib/cjs/ButtonPopupCheckbox.js +1 -1
- package/lib/cjs/ButtonPopupRadio.js +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/DnDList.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/ResponsibleContainer.d.ts +2 -7
- package/lib/cjs/ResponsibleContainer.js +8 -57
- package/lib/cjs/ScrollerListEx.d.ts +24 -9
- package/lib/cjs/ScrollerListEx.js +36 -39
- package/lib/cjs/SelectEx.js +2 -2
- package/lib/cjs/TableEx.d.ts +7 -0
- package/lib/cjs/TableEx.js +6 -12
- package/lib/cjs/app/ReactApp.d.ts +1 -3
- package/lib/cjs/custom/FieldDateInput.js +1 -1
- package/lib/cjs/custom/FieldInput.js +1 -1
- package/lib/cjs/custom/FieldJson.js +1 -1
- package/lib/cjs/custom/FieldNumberInput.js +1 -1
- package/lib/cjs/custom/FieldTexarea.js +1 -1
- package/lib/cjs/html/HtmlDiv.d.ts +24 -7
- package/lib/cjs/html/HtmlDiv.js +5 -1
- 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 +2 -7
- 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/ButtonPopupCheckbox.js +1 -1
- package/lib/mjs/ButtonPopupRadio.js +1 -1
- 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/DnDList.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/ResponsibleContainer.d.ts +2 -7
- package/lib/mjs/ResponsibleContainer.js +8 -57
- package/lib/mjs/ScrollerListEx.d.ts +24 -9
- package/lib/mjs/ScrollerListEx.js +36 -39
- package/lib/mjs/SelectEx.js +2 -2
- package/lib/mjs/TableEx.d.ts +7 -0
- package/lib/mjs/TableEx.js +6 -12
- package/lib/mjs/app/ReactApp.d.ts +1 -3
- package/lib/mjs/custom/FieldDateInput.js +1 -1
- package/lib/mjs/custom/FieldInput.js +1 -1
- package/lib/mjs/custom/FieldJson.js +1 -1
- package/lib/mjs/custom/FieldNumberInput.js +1 -1
- package/lib/mjs/custom/FieldTexarea.js +1 -1
- package/lib/mjs/html/HtmlDiv.d.ts +24 -7
- package/lib/mjs/html/HtmlDiv.js +2 -1
- 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 +2 -7
- 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/setupTests.ts +2 -0
- package/src/ButtonPopupCheckbox.tsx +1 -1
- package/src/ButtonPopupRadio.tsx +1 -1
- package/src/DataGridEx.tsx +151 -108
- package/src/DataGridRenderers.tsx +2 -1
- package/src/DnDList.tsx +1 -1
- package/src/MUUtils.ts +0 -33
- package/src/MobileListItemRenderer.tsx +2 -2
- package/src/ResponsibleContainer.tsx +21 -94
- package/src/ScrollerListEx.tsx +110 -122
- package/src/SelectEx.tsx +2 -2
- package/src/TableEx.tsx +20 -12
- package/src/custom/CustomFieldUtils.tsx +1 -1
- package/src/custom/FieldDateInput.tsx +1 -1
- package/src/custom/FieldInput.tsx +1 -1
- package/src/custom/FieldJson.tsx +1 -1
- package/src/custom/FieldNumberInput.tsx +1 -1
- package/src/custom/FieldTexarea.tsx +1 -1
- package/src/html/HtmlDiv.tsx +13 -9
- 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 +3 -11
- package/src/uses/useGridCacheInitLoad.ts +55 -0
- package/src/uses/useListCacheInitLoad.ts +51 -0
package/src/ScrollerListEx.tsx
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { css } from "@emotion/css";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
GridLoaderStates,
|
|
4
|
+
ScrollerList,
|
|
5
|
+
ScrollerListProps
|
|
6
|
+
} from "@etsoo/react";
|
|
3
7
|
import { DataTypes, Utils } from "@etsoo/shared";
|
|
4
8
|
import React from "react";
|
|
5
|
-
import { ListChildComponentProps } from "react-window";
|
|
6
9
|
import { MouseEventWithDataHandler, MUGlobal } from "./MUGlobal";
|
|
7
10
|
import { useTheme } from "@mui/material/styles";
|
|
11
|
+
import { GridUtils } from "./GridUtils";
|
|
12
|
+
import { useListCacheInitLoad } from "./uses/useListCacheInitLoad";
|
|
13
|
+
import Box from "@mui/material/Box";
|
|
8
14
|
|
|
9
15
|
// Scroll bar size
|
|
10
16
|
const scrollbarSize = 16;
|
|
@@ -84,12 +90,21 @@ const defaultMargin = (margin: object, horizon?: number | string) => {
|
|
|
84
90
|
/**
|
|
85
91
|
* Extended ScrollerList inner item renderer props
|
|
86
92
|
*/
|
|
87
|
-
export
|
|
88
|
-
extends ListChildComponentProps<T> {
|
|
93
|
+
export type ScrollerListExItemRendererProps<T> = {
|
|
89
94
|
/**
|
|
90
|
-
*
|
|
95
|
+
* Row index
|
|
91
96
|
*/
|
|
92
|
-
|
|
97
|
+
index: number;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Row data
|
|
101
|
+
*/
|
|
102
|
+
data: T;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Style
|
|
106
|
+
*/
|
|
107
|
+
style: React.CSSProperties;
|
|
93
108
|
|
|
94
109
|
/**
|
|
95
110
|
* Item height
|
|
@@ -105,7 +120,12 @@ export interface ScrollerListExInnerItemRendererProps<T>
|
|
|
105
120
|
* Default margins
|
|
106
121
|
*/
|
|
107
122
|
margins: object;
|
|
108
|
-
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Item selected
|
|
126
|
+
*/
|
|
127
|
+
selected: boolean;
|
|
128
|
+
};
|
|
109
129
|
|
|
110
130
|
/**
|
|
111
131
|
* Extended ScrollerList ItemSize type
|
|
@@ -123,7 +143,7 @@ export type ScrollerListExItemSize =
|
|
|
123
143
|
*/
|
|
124
144
|
export type ScrollerListExProps<T extends object> = Omit<
|
|
125
145
|
ScrollerListProps<T>,
|
|
126
|
-
"
|
|
146
|
+
"rowComponent" | "rowHeight" | "onClick" | "onDoubleClick" | "onInitLoad"
|
|
127
147
|
> & {
|
|
128
148
|
/**
|
|
129
149
|
* Alternating colors for odd/even rows
|
|
@@ -131,16 +151,19 @@ export type ScrollerListExProps<T extends object> = Omit<
|
|
|
131
151
|
alternatingColors?: [string?, string?];
|
|
132
152
|
|
|
133
153
|
/**
|
|
134
|
-
*
|
|
154
|
+
* Cache key
|
|
155
|
+
*/
|
|
156
|
+
cacheKey?: string;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Cache minutes
|
|
135
160
|
*/
|
|
136
|
-
|
|
137
|
-
props: ScrollerListExInnerItemRendererProps<T>
|
|
138
|
-
) => React.ReactNode;
|
|
161
|
+
cacheMinutes?: number;
|
|
139
162
|
|
|
140
163
|
/**
|
|
141
164
|
* Item renderer
|
|
142
165
|
*/
|
|
143
|
-
itemRenderer?: (props:
|
|
166
|
+
itemRenderer?: (props: ScrollerListExItemRendererProps<T>) => React.ReactNode;
|
|
144
167
|
|
|
145
168
|
/**
|
|
146
169
|
* Item size, a function indicates its a variable size list
|
|
@@ -168,92 +191,6 @@ export type ScrollerListExProps<T extends object> = Omit<
|
|
|
168
191
|
selectedColor?: string;
|
|
169
192
|
};
|
|
170
193
|
|
|
171
|
-
interface defaultItemRendererProps<T> extends ListChildComponentProps<T> {
|
|
172
|
-
/**
|
|
173
|
-
* onMouseDown callback
|
|
174
|
-
*/
|
|
175
|
-
onMouseDown: (div: HTMLDivElement, data: T) => void;
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Inner item renderer
|
|
179
|
-
*/
|
|
180
|
-
innerItemRenderer: (
|
|
181
|
-
props: ScrollerListExInnerItemRendererProps<T>
|
|
182
|
-
) => React.ReactNode;
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Item height
|
|
186
|
-
*/
|
|
187
|
-
itemHeight: number;
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Double click handler
|
|
191
|
-
*/
|
|
192
|
-
onDoubleClick?: MouseEventWithDataHandler<T>;
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Click handler
|
|
196
|
-
*/
|
|
197
|
-
onClick?: MouseEventWithDataHandler<T>;
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Item space
|
|
201
|
-
*/
|
|
202
|
-
space: number;
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Default margins
|
|
206
|
-
*/
|
|
207
|
-
margins: object;
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Item selected
|
|
211
|
-
*/
|
|
212
|
-
selected: boolean;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Default itemRenderer
|
|
216
|
-
function defaultItemRenderer<T>({
|
|
217
|
-
index,
|
|
218
|
-
innerItemRenderer,
|
|
219
|
-
data,
|
|
220
|
-
onMouseDown,
|
|
221
|
-
selected,
|
|
222
|
-
style,
|
|
223
|
-
itemHeight,
|
|
224
|
-
onClick,
|
|
225
|
-
onDoubleClick,
|
|
226
|
-
space,
|
|
227
|
-
margins
|
|
228
|
-
}: defaultItemRendererProps<T>) {
|
|
229
|
-
// Child
|
|
230
|
-
const child = innerItemRenderer({
|
|
231
|
-
index,
|
|
232
|
-
data,
|
|
233
|
-
style,
|
|
234
|
-
selected,
|
|
235
|
-
itemHeight,
|
|
236
|
-
space,
|
|
237
|
-
margins
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
let rowClass = `ScrollerListEx-Row${index % 2}`;
|
|
241
|
-
if (selected) rowClass += ` ${selectedClassName}`;
|
|
242
|
-
|
|
243
|
-
// Layout
|
|
244
|
-
return (
|
|
245
|
-
<div
|
|
246
|
-
className={rowClass}
|
|
247
|
-
style={style}
|
|
248
|
-
onMouseDown={(event) => onMouseDown(event.currentTarget, data)}
|
|
249
|
-
onClick={(event) => onClick && onClick(event, data)}
|
|
250
|
-
onDoubleClick={(event) => onDoubleClick && onDoubleClick(event, data)}
|
|
251
|
-
>
|
|
252
|
-
{child}
|
|
253
|
-
</div>
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
194
|
/**
|
|
258
195
|
* Extended ScrollerList
|
|
259
196
|
* @param props Props
|
|
@@ -263,7 +200,7 @@ export function ScrollerListEx<T extends object>(
|
|
|
263
200
|
props: ScrollerListExProps<T>
|
|
264
201
|
) {
|
|
265
202
|
// Selected item ref
|
|
266
|
-
const selectedItem = React.useRef<[HTMLDivElement, T]>();
|
|
203
|
+
const selectedItem = React.useRef<[HTMLDivElement, T]>(null);
|
|
267
204
|
|
|
268
205
|
const onMouseDown = (div: HTMLDivElement, data: T) => {
|
|
269
206
|
// Destruct
|
|
@@ -293,30 +230,32 @@ export function ScrollerListEx<T extends object>(
|
|
|
293
230
|
const {
|
|
294
231
|
alternatingColors = [undefined, undefined],
|
|
295
232
|
className,
|
|
233
|
+
cacheKey,
|
|
234
|
+
cacheMinutes = 15,
|
|
296
235
|
idField = "id" as DataTypes.Keys<T>,
|
|
297
|
-
innerItemRenderer,
|
|
298
236
|
itemSize,
|
|
299
|
-
itemRenderer = (
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
...itemProps
|
|
311
|
-
});
|
|
312
|
-
},
|
|
237
|
+
itemRenderer = ({ data, itemHeight, margins }) => (
|
|
238
|
+
<Box
|
|
239
|
+
component="pre"
|
|
240
|
+
sx={{
|
|
241
|
+
height: itemHeight,
|
|
242
|
+
...margins
|
|
243
|
+
}}
|
|
244
|
+
>
|
|
245
|
+
{JSON.stringify(data)}
|
|
246
|
+
</Box>
|
|
247
|
+
),
|
|
313
248
|
onClick,
|
|
314
249
|
onDoubleClick,
|
|
250
|
+
onUpdateRows,
|
|
315
251
|
onSelectChange,
|
|
316
252
|
selectedColor = "#edf4fb",
|
|
317
253
|
...rest
|
|
318
254
|
} = props;
|
|
319
255
|
|
|
256
|
+
// Init handler
|
|
257
|
+
const initHandler = useListCacheInitLoad<T>(cacheKey, cacheMinutes);
|
|
258
|
+
|
|
320
259
|
// Theme
|
|
321
260
|
const theme = useTheme();
|
|
322
261
|
|
|
@@ -346,11 +285,13 @@ export function ScrollerListEx<T extends object>(
|
|
|
346
285
|
return itemSizeResult!;
|
|
347
286
|
};
|
|
348
287
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
288
|
+
const onUpdateRowsHandler = React.useCallback(
|
|
289
|
+
(rows: T[], state: GridLoaderStates<T>) => {
|
|
290
|
+
GridUtils.getUpdateRowsHandler<T>(cacheKey)?.(rows, state);
|
|
291
|
+
onUpdateRows?.(rows, state);
|
|
292
|
+
},
|
|
293
|
+
[onUpdateRows, cacheKey]
|
|
294
|
+
);
|
|
354
295
|
|
|
355
296
|
// Layout
|
|
356
297
|
return (
|
|
@@ -361,8 +302,55 @@ export function ScrollerListEx<T extends object>(
|
|
|
361
302
|
createGridStyle(alternatingColors, selectedColor)
|
|
362
303
|
)}
|
|
363
304
|
idField={idField}
|
|
364
|
-
|
|
365
|
-
|
|
305
|
+
onRowsRendered={
|
|
306
|
+
cacheKey
|
|
307
|
+
? (visibleRows) =>
|
|
308
|
+
sessionStorage.setItem(
|
|
309
|
+
`${cacheKey}-scroll`,
|
|
310
|
+
JSON.stringify(visibleRows)
|
|
311
|
+
)
|
|
312
|
+
: undefined
|
|
313
|
+
}
|
|
314
|
+
onInitLoad={initHandler}
|
|
315
|
+
onUpdateRows={onUpdateRowsHandler}
|
|
316
|
+
rowComponent={({ index, items, style }) => {
|
|
317
|
+
const data = items[index];
|
|
318
|
+
const selected = isSelected(data);
|
|
319
|
+
const rowClass = `ScrollerListEx-Row${index % 2}${
|
|
320
|
+
selected ? ` ${selectedClassName}` : ""
|
|
321
|
+
}`;
|
|
322
|
+
|
|
323
|
+
const [itemHeight, space, margins] = calculateItemSize(index);
|
|
324
|
+
|
|
325
|
+
// Child
|
|
326
|
+
const child = itemRenderer({
|
|
327
|
+
index,
|
|
328
|
+
data,
|
|
329
|
+
style,
|
|
330
|
+
selected,
|
|
331
|
+
itemHeight,
|
|
332
|
+
space,
|
|
333
|
+
margins
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
return (
|
|
337
|
+
<div
|
|
338
|
+
className={rowClass}
|
|
339
|
+
style={style}
|
|
340
|
+
onMouseDown={(event) => onMouseDown(event.currentTarget, data)}
|
|
341
|
+
onClick={(event) => onClick && onClick(event, data)}
|
|
342
|
+
onDoubleClick={(event) =>
|
|
343
|
+
onDoubleClick && onDoubleClick(event, data)
|
|
344
|
+
}
|
|
345
|
+
>
|
|
346
|
+
{child}
|
|
347
|
+
</div>
|
|
348
|
+
);
|
|
349
|
+
}}
|
|
350
|
+
rowHeight={(index) => {
|
|
351
|
+
const [size, space] = calculateItemSize(index);
|
|
352
|
+
return size + space;
|
|
353
|
+
}}
|
|
366
354
|
{...rest}
|
|
367
355
|
/>
|
|
368
356
|
);
|
package/src/SelectEx.tsx
CHANGED
|
@@ -210,7 +210,7 @@ export function SelectEx<
|
|
|
210
210
|
|
|
211
211
|
// Value state
|
|
212
212
|
const [valueState, setValueStateBase] = React.useState<unknown>(valueSource);
|
|
213
|
-
const valueRef = React.useRef<unknown>();
|
|
213
|
+
const valueRef = React.useRef<unknown>(null);
|
|
214
214
|
const setValueState = (newValue: unknown) => {
|
|
215
215
|
valueRef.current = newValue;
|
|
216
216
|
setValueStateBase(newValue);
|
|
@@ -268,7 +268,7 @@ export function SelectEx<
|
|
|
268
268
|
};
|
|
269
269
|
|
|
270
270
|
// Refs
|
|
271
|
-
const divRef = React.useRef<HTMLDivElement>();
|
|
271
|
+
const divRef = React.useRef<HTMLDivElement>(null);
|
|
272
272
|
|
|
273
273
|
// Refresh list data
|
|
274
274
|
const refreshData = () => {
|
package/src/TableEx.tsx
CHANGED
|
@@ -7,7 +7,8 @@ import {
|
|
|
7
7
|
GridLoaderPartialStates,
|
|
8
8
|
GridLoaderStates,
|
|
9
9
|
GridMethodRef,
|
|
10
|
-
GridSizeGet
|
|
10
|
+
GridSizeGet,
|
|
11
|
+
ScrollToRowParam
|
|
11
12
|
} from "@etsoo/react";
|
|
12
13
|
import { DataTypes, IdDefaultType } from "@etsoo/shared";
|
|
13
14
|
import React from "react";
|
|
@@ -77,6 +78,14 @@ export type TableExProps<
|
|
|
77
78
|
*/
|
|
78
79
|
mRef?: React.Ref<TableExMethodRef<T>>;
|
|
79
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Data change handler
|
|
83
|
+
* @param rows Rows
|
|
84
|
+
* @param rowIndex Row index
|
|
85
|
+
* @param columnIndex Column index
|
|
86
|
+
*/
|
|
87
|
+
onDataChange?: (rows: T[], rowIndex: number, columnIndex: number) => void;
|
|
88
|
+
|
|
80
89
|
/**
|
|
81
90
|
* On items select change
|
|
82
91
|
*/
|
|
@@ -117,6 +126,7 @@ export function TableEx<
|
|
|
117
126
|
loadData,
|
|
118
127
|
maxHeight,
|
|
119
128
|
mRef,
|
|
129
|
+
onDataChange,
|
|
120
130
|
onSelectChange,
|
|
121
131
|
rowHeight = 53,
|
|
122
132
|
otherHeight = 110,
|
|
@@ -183,6 +193,10 @@ export function TableEx<
|
|
|
183
193
|
React.useImperativeHandle(
|
|
184
194
|
mRef,
|
|
185
195
|
() => ({
|
|
196
|
+
get element() {
|
|
197
|
+
return null;
|
|
198
|
+
},
|
|
199
|
+
|
|
186
200
|
delete(index) {
|
|
187
201
|
const item = rows.at(index);
|
|
188
202
|
if (item) {
|
|
@@ -192,27 +206,20 @@ export function TableEx<
|
|
|
192
206
|
}
|
|
193
207
|
return item;
|
|
194
208
|
},
|
|
209
|
+
|
|
195
210
|
insert(item, start) {
|
|
196
211
|
const newRows = [...rows];
|
|
197
212
|
newRows.splice(start, 0, item);
|
|
198
213
|
setRows(newRows);
|
|
199
214
|
},
|
|
200
|
-
|
|
201
|
-
* Refresh data
|
|
202
|
-
*/
|
|
215
|
+
|
|
203
216
|
refresh(): void {
|
|
204
217
|
loadDataLocal();
|
|
205
218
|
},
|
|
206
219
|
|
|
207
|
-
/**
|
|
208
|
-
* Reset
|
|
209
|
-
*/
|
|
210
220
|
reset,
|
|
211
|
-
scrollToRef(scrollOffset: number): void {
|
|
212
|
-
// Not implemented
|
|
213
|
-
},
|
|
214
221
|
|
|
215
|
-
|
|
222
|
+
scrollToRow(param: ScrollToRowParam): void {
|
|
216
223
|
// Not implemented
|
|
217
224
|
}
|
|
218
225
|
}),
|
|
@@ -513,7 +520,8 @@ export function TableEx<
|
|
|
513
520
|
rowIndex,
|
|
514
521
|
columnIndex,
|
|
515
522
|
cellProps,
|
|
516
|
-
|
|
523
|
+
triggerChange: () =>
|
|
524
|
+
onDataChange?.(rows, rowIndex, columnIndex)
|
|
517
525
|
})
|
|
518
526
|
) : (
|
|
519
527
|
<React.Fragment> </React.Fragment>
|
|
@@ -16,7 +16,7 @@ export const FieldDateInput: ICustomFieldReact<Date> = ({
|
|
|
16
16
|
defaultValue
|
|
17
17
|
}) => {
|
|
18
18
|
// Ref
|
|
19
|
-
const inputRef = React.useRef<HTMLInputElement>();
|
|
19
|
+
const inputRef = React.useRef<HTMLInputElement>(null);
|
|
20
20
|
|
|
21
21
|
const getValue = () =>
|
|
22
22
|
inputRef.current == null
|
|
@@ -15,7 +15,7 @@ export const FieldInput: ICustomFieldReact<string> = ({
|
|
|
15
15
|
defaultValue
|
|
16
16
|
}) => {
|
|
17
17
|
// Ref
|
|
18
|
-
const inputRef = React.useRef<HTMLInputElement>();
|
|
18
|
+
const inputRef = React.useRef<HTMLInputElement>(null);
|
|
19
19
|
|
|
20
20
|
const getValue = () => inputRef.current?.value;
|
|
21
21
|
|
package/src/custom/FieldJson.tsx
CHANGED
|
@@ -26,7 +26,7 @@ export const FieldJson: ICustomFieldReact<object> = ({
|
|
|
26
26
|
defaultValue
|
|
27
27
|
}) => {
|
|
28
28
|
// Ref
|
|
29
|
-
const inputRef = React.useRef<HTMLInputElement>();
|
|
29
|
+
const inputRef = React.useRef<HTMLInputElement>(null);
|
|
30
30
|
|
|
31
31
|
const getValue = () => parseJson(inputRef.current?.value);
|
|
32
32
|
|
|
@@ -16,7 +16,7 @@ export const FieldNumberInput: ICustomFieldReact<number> = ({
|
|
|
16
16
|
defaultValue
|
|
17
17
|
}) => {
|
|
18
18
|
// Ref
|
|
19
|
-
const inputRef = React.useRef<HTMLInputElement>();
|
|
19
|
+
const inputRef = React.useRef<HTMLInputElement>(null);
|
|
20
20
|
|
|
21
21
|
const getValue = () => {
|
|
22
22
|
const value = inputRef.current?.valueAsNumber;
|
|
@@ -15,7 +15,7 @@ export const FieldTexarea: ICustomFieldReact<string> = ({
|
|
|
15
15
|
defaultValue
|
|
16
16
|
}) => {
|
|
17
17
|
// Ref
|
|
18
|
-
const inputRef = React.useRef<HTMLInputElement>();
|
|
18
|
+
const inputRef = React.useRef<HTMLInputElement>(null);
|
|
19
19
|
|
|
20
20
|
const getValue = () => inputRef.current?.value;
|
|
21
21
|
|
package/src/html/HtmlDiv.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Utils } from "@etsoo/shared";
|
|
2
2
|
import { HTMLAttributes } from "react";
|
|
3
|
+
import DOMPurify from "dompurify";
|
|
3
4
|
|
|
4
5
|
class HtmlDivElement extends HTMLElement {
|
|
5
6
|
static get observedAttributes() {
|
|
@@ -96,7 +97,7 @@ class HtmlDivElement extends HTMLElement {
|
|
|
96
97
|
) {
|
|
97
98
|
wrapper.innerHTML = this.textContent;
|
|
98
99
|
} else {
|
|
99
|
-
wrapper.innerHTML = html;
|
|
100
|
+
wrapper.innerHTML = DOMPurify.sanitize(html);
|
|
100
101
|
}
|
|
101
102
|
|
|
102
103
|
this.textContent = null; // Clear the textContent to avoid duplication
|
|
@@ -108,6 +109,17 @@ if (!customElements.get("html-div")) {
|
|
|
108
109
|
customElements.define("html-div", HtmlDivElement);
|
|
109
110
|
}
|
|
110
111
|
|
|
112
|
+
declare module "react" {
|
|
113
|
+
namespace JSX {
|
|
114
|
+
interface IntrinsicElements {
|
|
115
|
+
"html-div": React.DetailedHTMLProps<
|
|
116
|
+
React.HTMLAttributes<HtmlDivElement>,
|
|
117
|
+
HtmlDivElement
|
|
118
|
+
>;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
111
123
|
/**
|
|
112
124
|
* Custom HTML element properties
|
|
113
125
|
* 自定义 HTML 元素属性
|
|
@@ -120,14 +132,6 @@ export type HtmlDivProps = HTMLAttributes<HTMLElement> & {
|
|
|
120
132
|
displayStyle?: string;
|
|
121
133
|
};
|
|
122
134
|
|
|
123
|
-
declare global {
|
|
124
|
-
namespace JSX {
|
|
125
|
-
interface IntrinsicElements {
|
|
126
|
-
"html-div": React.HTMLAttributes<HTMLElement>;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
135
|
/**
|
|
132
136
|
* Custom HTML element that sanitizes and displays HTML content
|
|
133
137
|
* 自定义 HTML 元素,用于清理和显示 HTML 内容
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
GridLoadDataProps,
|
|
3
|
-
GridLoaderStates,
|
|
4
|
-
GridOnScrollProps,
|
|
5
3
|
ScrollerGridForwardRef,
|
|
6
|
-
VariableSizeGrid,
|
|
7
4
|
useCombinedRefs,
|
|
8
5
|
useDimensions,
|
|
9
6
|
useSearchParamsWithCache
|
|
@@ -66,12 +63,13 @@ export function DataGridPage<T extends object, F>(
|
|
|
66
63
|
(ref: ScrollerGridForwardRef<T> | null | undefined) => {
|
|
67
64
|
if (ref == null) return;
|
|
68
65
|
states.ref = ref;
|
|
66
|
+
|
|
67
|
+
if (ref.element) setStates({ element: ref.element });
|
|
68
|
+
|
|
69
69
|
//setStates({ ref });
|
|
70
70
|
}
|
|
71
71
|
);
|
|
72
72
|
|
|
73
|
-
const initLoadedRef = React.useRef<boolean>();
|
|
74
|
-
|
|
75
73
|
// On submit callback
|
|
76
74
|
const onSubmit = (data: FormData, _reset: boolean) => {
|
|
77
75
|
setStates({ data });
|
|
@@ -87,44 +85,6 @@ export function DataGridPage<T extends object, F>(
|
|
|
87
85
|
// Search data
|
|
88
86
|
const searchData = useSearchParamsWithCache(cacheKey);
|
|
89
87
|
|
|
90
|
-
const onInitLoad = (
|
|
91
|
-
ref: VariableSizeGrid<T>
|
|
92
|
-
): [T[], Partial<GridLoaderStates<T>>?] | null | undefined => {
|
|
93
|
-
// Avoid repeatedly load from cache
|
|
94
|
-
if (initLoadedRef.current || !cacheKey) return undefined;
|
|
95
|
-
|
|
96
|
-
// Cache data
|
|
97
|
-
const cacheData = GridUtils.getCacheData<T>(cacheKey, cacheMinutes);
|
|
98
|
-
if (cacheData) {
|
|
99
|
-
const { rows, state } = cacheData;
|
|
100
|
-
|
|
101
|
-
GridUtils.mergeSearchData(state, searchData);
|
|
102
|
-
|
|
103
|
-
// Scroll position
|
|
104
|
-
const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
|
|
105
|
-
if (scrollData) {
|
|
106
|
-
const { scrollLeft, scrollTop } = JSON.parse(
|
|
107
|
-
scrollData
|
|
108
|
-
) as GridOnScrollProps;
|
|
109
|
-
|
|
110
|
-
globalThis.setTimeout(() => ref.scrollTo({ scrollLeft, scrollTop }), 0);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Update flag value
|
|
114
|
-
initLoadedRef.current = true;
|
|
115
|
-
|
|
116
|
-
// Return cached rows and state
|
|
117
|
-
return [rows, state];
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return undefined;
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
const onGridScroll = (props: GridOnScrollProps) => {
|
|
124
|
-
if (!cacheKey || !initLoadedRef.current) return;
|
|
125
|
-
sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
|
|
126
|
-
};
|
|
127
|
-
|
|
128
88
|
// Watch container
|
|
129
89
|
const { dimensions } = useDimensions(1, undefined, sizeReadyMiliseconds);
|
|
130
90
|
const rect = dimensions[0][2];
|
|
@@ -159,12 +119,6 @@ export function DataGridPage<T extends object, F>(
|
|
|
159
119
|
height={gridHeight}
|
|
160
120
|
loadData={localLoadData}
|
|
161
121
|
mRef={refs}
|
|
162
|
-
onUpdateRows={GridUtils.getUpdateRowsHandler<T>(cacheKey)}
|
|
163
|
-
onInitLoad={onInitLoad}
|
|
164
|
-
onScroll={onGridScroll}
|
|
165
|
-
outerRef={(element?: HTMLDivElement) => {
|
|
166
|
-
if (element != null) setStates({ element });
|
|
167
|
-
}}
|
|
168
122
|
{...rest}
|
|
169
123
|
/>
|
|
170
124
|
);
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
GridLoadDataProps,
|
|
3
|
-
GridLoaderStates,
|
|
4
|
-
ListOnScrollProps,
|
|
5
3
|
ScrollerListForwardRef,
|
|
6
|
-
ScrollerListRef,
|
|
7
4
|
useCombinedRefs,
|
|
8
5
|
useDimensions,
|
|
9
6
|
useSearchParamsWithCache
|
|
@@ -56,8 +53,6 @@ export function FixedListPage<T extends object, F>(
|
|
|
56
53
|
ref?: ScrollerListForwardRef<T>;
|
|
57
54
|
}>({});
|
|
58
55
|
|
|
59
|
-
const initLoadedRef = React.useRef<boolean>();
|
|
60
|
-
|
|
61
56
|
// Scroll container
|
|
62
57
|
const [scrollContainer, updateScrollContainer] = React.useState<
|
|
63
58
|
HTMLElement | undefined
|
|
@@ -72,6 +67,8 @@ export function FixedListPage<T extends object, F>(
|
|
|
72
67
|
|
|
73
68
|
states.ref = ref;
|
|
74
69
|
|
|
70
|
+
if (ref.element) updateScrollContainer(ref.element);
|
|
71
|
+
|
|
75
72
|
if (first) reset();
|
|
76
73
|
}
|
|
77
74
|
);
|
|
@@ -94,44 +91,6 @@ export function FixedListPage<T extends object, F>(
|
|
|
94
91
|
);
|
|
95
92
|
};
|
|
96
93
|
|
|
97
|
-
// Search data
|
|
98
|
-
const searchData = useSearchParamsWithCache(cacheKey);
|
|
99
|
-
|
|
100
|
-
const onInitLoad = (
|
|
101
|
-
ref: ScrollerListRef
|
|
102
|
-
): [T[], Partial<GridLoaderStates<T>>?] | null | undefined => {
|
|
103
|
-
// Avoid repeatedly load from cache
|
|
104
|
-
if (initLoadedRef.current || !cacheKey) return undefined;
|
|
105
|
-
|
|
106
|
-
// Cache data
|
|
107
|
-
const cacheData = GridUtils.getCacheData<T>(cacheKey, cacheMinutes);
|
|
108
|
-
if (cacheData) {
|
|
109
|
-
const { rows, state } = cacheData;
|
|
110
|
-
|
|
111
|
-
GridUtils.mergeSearchData(state, searchData);
|
|
112
|
-
|
|
113
|
-
// Scroll position
|
|
114
|
-
const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
|
|
115
|
-
if (scrollData) {
|
|
116
|
-
const { scrollOffset } = JSON.parse(scrollData) as ListOnScrollProps;
|
|
117
|
-
globalThis.setTimeout(() => ref.scrollTo(scrollOffset), 0);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Update flag value
|
|
121
|
-
initLoadedRef.current = true;
|
|
122
|
-
|
|
123
|
-
// Return cached rows and state
|
|
124
|
-
return [rows, state];
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return undefined;
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
const onListScroll = (props: ListOnScrollProps) => {
|
|
131
|
-
if (!cacheKey || !initLoadedRef.current) return;
|
|
132
|
-
sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
|
|
133
|
-
};
|
|
134
|
-
|
|
135
94
|
// Watch container
|
|
136
95
|
const { dimensions } = useDimensions(1, undefined, sizeReadyMiliseconds);
|
|
137
96
|
const rect = dimensions[0][2];
|
|
@@ -159,12 +118,6 @@ export function FixedListPage<T extends object, F>(
|
|
|
159
118
|
height={height}
|
|
160
119
|
loadData={localLoadData}
|
|
161
120
|
mRef={refs}
|
|
162
|
-
onUpdateRows={GridUtils.getUpdateRowsHandler<T>(cacheKey)}
|
|
163
|
-
onInitLoad={onInitLoad}
|
|
164
|
-
onScroll={onListScroll}
|
|
165
|
-
oRef={(element) => {
|
|
166
|
-
if (element != null) updateScrollContainer(element);
|
|
167
|
-
}}
|
|
168
121
|
{...rest}
|
|
169
122
|
/>
|
|
170
123
|
</Box>
|
|
@@ -172,6 +125,9 @@ export function FixedListPage<T extends object, F>(
|
|
|
172
125
|
}
|
|
173
126
|
}, [rect]);
|
|
174
127
|
|
|
128
|
+
// Search data
|
|
129
|
+
const searchData = useSearchParamsWithCache(cacheKey);
|
|
130
|
+
|
|
175
131
|
const f = typeof fields == "function" ? fields(searchData ?? {}) : fields;
|
|
176
132
|
|
|
177
133
|
const { paddings, ...pageRest } = pageProps;
|