@azrico/reactgrid 1.5.1 → 1.6.0
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/CHANGELOG.md +10 -0
- package/README.md +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +35 -1
- package/dist/src/func/func_a11y.d.ts +5 -0
- package/dist/src/func/func_a11y.js +10 -1
- package/dist/src/func/func_child.js +15 -7
- package/dist/src/func/func_grid.d.ts +4 -1
- package/dist/src/func/func_grid.js +10 -3
- package/dist/src/hooks/useColumnData.d.ts +1 -1
- package/dist/src/hooks/useColumnData.js +8 -12
- package/dist/src/hooks/useDatasource.js +13 -2
- package/dist/src/hooks/useGridEvents.d.ts +3 -0
- package/dist/src/hooks/useGridEvents.js +21 -9
- package/dist/src/hooks/useGridSearch.d.ts +3 -3
- package/dist/src/hooks/useGridSearch.js +68 -42
- package/dist/src/types/types.d.ts +15 -3
- package/dist/src/views/DataGrid.js +35 -16
- package/index.ts +5 -0
- package/package.json +1 -1
- package/src/func/func_a11y.ts +10 -0
- package/src/func/func_child.ts +92 -83
- package/src/func/func_grid.ts +16 -3
- package/src/hooks/useColumnData.ts +28 -34
- package/src/hooks/useDatasource.ts +32 -25
- package/src/hooks/useGridEvents.ts +40 -24
- package/src/hooks/useGridSearch.tsx +106 -79
- package/src/types/types.ts +16 -2
- package/src/views/DataGrid.tsx +362 -318
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
|
+
|
|
5
|
+
### 1.6.0 (2026-10-14)
|
|
6
|
+
|
|
7
|
+
* Pass `filterValue`, `sortInfo` and `groupBy` to a `dataSource` function next to `skip`, `limit`, `cached_data` and `last_cache_info`, so header filters can drive a server-side search.
|
|
8
|
+
* With `gridOptions.remoteFilter` / `remoteSort`, a filter or sort change invalidates the data cache and calls `dataSource` again. Local filtering and sorting still reuse the cached rows.
|
|
9
|
+
* Export the typed `AzDataSourceParams` and `AzDataSourceFunc` for the `dataSource` and `details_dataSource` props.
|
|
10
|
+
* Re-export `SelectFilter`, `NumberFilter`, `DateFilter` and `BoolFilter` for `column.filterEditor`.
|
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ The grid exposes ARIA grid semantics, so screen readers and automation tools can
|
|
|
22
22
|
|
|
23
23
|
| Element | Attributes |
|
|
24
24
|
| --- | --- |
|
|
25
|
-
| Grid root | `role="grid"`, `aria-rowcount` (total rows incl. header; the full data count when paginated), `aria-colcount` (visible columns), `aria-label`, `aria-readonly="true"` when the grid isn't editable |
|
|
25
|
+
| Grid root | `role="grid"`, `aria-rowcount` (total rows incl. header; the full data count when paginated), `aria-colcount` (visible columns), `aria-label`, `aria-readonly="true"` when the grid isn't editable, `aria-busy="true"` while loading |
|
|
26
26
|
| Header row | `role="row"`, `aria-rowindex="1"` |
|
|
27
27
|
| Header cells | `role="columnheader"`, `aria-colindex`, `aria-sort` (`ascending` / `descending` / `none`, sortable columns only) |
|
|
28
28
|
| Rows | `role="row"`, `aria-rowindex` (1-based, header is 1, includes the page offset), `aria-selected` when selection is enabled, `data-row-id` |
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
export * from './src/views/DataGrid';
|
|
2
2
|
export * from './src/types/types';
|
|
3
3
|
export { get_row_id, set_row_id, get_col_name, get_col_header } from './src/func/func_grid';
|
|
4
|
+
export { default as SelectFilter } from '@inovua/reactdatagrid-enterprise/SelectFilter';
|
|
5
|
+
export { default as NumberFilter } from '@inovua/reactdatagrid-enterprise/NumberFilter';
|
|
6
|
+
export { default as DateFilter } from '@inovua/reactdatagrid-enterprise/DateFilter';
|
|
7
|
+
export { default as BoolFilter } from '@inovua/reactdatagrid-enterprise/BoolFilter';
|
|
4
8
|
import { AzGrid } from './src/views/DataGrid';
|
|
5
9
|
export default AzGrid;
|
package/dist/index.js
CHANGED
|
@@ -7,8 +7,36 @@ var _exportNames = {
|
|
|
7
7
|
get_row_id: true,
|
|
8
8
|
set_row_id: true,
|
|
9
9
|
get_col_name: true,
|
|
10
|
-
get_col_header: true
|
|
10
|
+
get_col_header: true,
|
|
11
|
+
SelectFilter: true,
|
|
12
|
+
NumberFilter: true,
|
|
13
|
+
DateFilter: true,
|
|
14
|
+
BoolFilter: true
|
|
11
15
|
};
|
|
16
|
+
Object.defineProperty(exports, "BoolFilter", {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: function () {
|
|
19
|
+
return _BoolFilter.default;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
Object.defineProperty(exports, "DateFilter", {
|
|
23
|
+
enumerable: true,
|
|
24
|
+
get: function () {
|
|
25
|
+
return _DateFilter.default;
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
Object.defineProperty(exports, "NumberFilter", {
|
|
29
|
+
enumerable: true,
|
|
30
|
+
get: function () {
|
|
31
|
+
return _NumberFilter.default;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
Object.defineProperty(exports, "SelectFilter", {
|
|
35
|
+
enumerable: true,
|
|
36
|
+
get: function () {
|
|
37
|
+
return _SelectFilter.default;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
12
40
|
exports.default = void 0;
|
|
13
41
|
Object.defineProperty(exports, "get_col_header", {
|
|
14
42
|
enumerable: true,
|
|
@@ -59,4 +87,10 @@ Object.keys(_types).forEach(function (key) {
|
|
|
59
87
|
});
|
|
60
88
|
});
|
|
61
89
|
var _func_grid = require("./src/func/func_grid");
|
|
90
|
+
var _SelectFilter = _interopRequireDefault(require("@inovua/reactdatagrid-enterprise/SelectFilter"));
|
|
91
|
+
var _NumberFilter = _interopRequireDefault(require("@inovua/reactdatagrid-enterprise/NumberFilter"));
|
|
92
|
+
var _DateFilter = _interopRequireDefault(require("@inovua/reactdatagrid-enterprise/DateFilter"));
|
|
93
|
+
var _BoolFilter = _interopRequireDefault(require("@inovua/reactdatagrid-enterprise/BoolFilter"));
|
|
94
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
95
|
+
// filter editors for column.filterEditor, so consumers don't import @inovua directly
|
|
62
96
|
var _default = exports.default = _DataGrid.AzGrid;
|
|
@@ -31,6 +31,11 @@ export type RootA11yOptions = {
|
|
|
31
31
|
ariaLabel?: string;
|
|
32
32
|
editable?: boolean;
|
|
33
33
|
};
|
|
34
|
+
/**
|
|
35
|
+
* true while the grid is loading (loading prop or async datasource)
|
|
36
|
+
* @param grid computed props of the grid
|
|
37
|
+
*/
|
|
38
|
+
export declare function is_grid_busy(grid: GridType | null | undefined): boolean;
|
|
34
39
|
/**
|
|
35
40
|
* root element of the grid, null when it isn't mounted
|
|
36
41
|
* @param grid computed props of the grid
|
|
@@ -9,6 +9,7 @@ exports.apply_row_a11y = apply_row_a11y;
|
|
|
9
9
|
exports.get_grid_root = get_grid_root;
|
|
10
10
|
exports.get_grid_row_count = get_grid_row_count;
|
|
11
11
|
exports.get_root_a11y_key = get_root_a11y_key;
|
|
12
|
+
exports.is_grid_busy = is_grid_busy;
|
|
12
13
|
function set_default(target, key, value) {
|
|
13
14
|
if (target[key] === undefined && value !== undefined && value !== null) target[key] = value;
|
|
14
15
|
}
|
|
@@ -100,6 +101,13 @@ function get_grid_row_count(grid) {
|
|
|
100
101
|
const offset = g.computedLivePagination ? 0 : g.computedSkip || 0;
|
|
101
102
|
return Math.max(g.paginationCount || 0, offset + rendered);
|
|
102
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* true while the grid is loading (loading prop or async datasource)
|
|
106
|
+
* @param grid computed props of the grid
|
|
107
|
+
*/
|
|
108
|
+
function is_grid_busy(grid) {
|
|
109
|
+
return !!(grid !== null && grid !== void 0 && grid.computedLoading);
|
|
110
|
+
}
|
|
103
111
|
/**
|
|
104
112
|
* root element of the grid, null when it isn't mounted
|
|
105
113
|
* @param grid computed props of the grid
|
|
@@ -117,7 +125,7 @@ function get_root_a11y_key(grid, options) {
|
|
|
117
125
|
var _options$ariaLabel;
|
|
118
126
|
const g = grid;
|
|
119
127
|
if (!g) return '';
|
|
120
|
-
return [get_grid_row_count(g), (g.visibleColumns || []).length, (_options$ariaLabel = options.ariaLabel) !== null && _options$ariaLabel !== void 0 ? _options$ariaLabel : '', options.editable ? 1 : 0].join('|');
|
|
128
|
+
return [get_grid_row_count(g), (g.visibleColumns || []).length, (_options$ariaLabel = options.ariaLabel) !== null && _options$ariaLabel !== void 0 ? _options$ariaLabel : '', options.editable ? 1 : 0, is_grid_busy(g) ? 1 : 0].join('|');
|
|
121
129
|
}
|
|
122
130
|
/**
|
|
123
131
|
* sets ARIA attributes on the grid root element
|
|
@@ -135,5 +143,6 @@ function apply_root_a11y(grid, options) {
|
|
|
135
143
|
set_attr(el, 'aria-colcount', (g.visibleColumns || []).length);
|
|
136
144
|
set_attr(el, 'aria-label', options.ariaLabel);
|
|
137
145
|
set_attr(el, 'aria-readonly', options.editable ? undefined : 'true');
|
|
146
|
+
set_attr(el, 'aria-busy', is_grid_busy(g) ? 'true' : undefined);
|
|
138
147
|
return el;
|
|
139
148
|
}
|
|
@@ -27,23 +27,31 @@ function fix_parent_child_relations(rows) {
|
|
|
27
27
|
};
|
|
28
28
|
});
|
|
29
29
|
const top_level_rows = converted_rows.filter(r => !r.parent);
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
//group rows by parent id once, instead of scanning all rows for every parent
|
|
31
|
+
const children_by_parent = new Map();
|
|
32
|
+
for (let index = 0; index < converted_rows.length; index++) {
|
|
33
|
+
const r = converted_rows[index];
|
|
34
|
+
if (!r.parent) continue;
|
|
35
|
+
const key = String(r.parent);
|
|
36
|
+
const siblings = children_by_parent.get(key);
|
|
37
|
+
if (siblings) siblings.push(r);else children_by_parent.set(key, [r]);
|
|
38
|
+
}
|
|
39
|
+
if (children_by_parent.size > 0) {
|
|
32
40
|
//find children of top-level parents:
|
|
33
41
|
for (let index = 0; index < top_level_rows.length; index++) {
|
|
34
42
|
const mrow = top_level_rows[index];
|
|
35
|
-
assign_children(mrow,
|
|
43
|
+
assign_children(mrow, children_by_parent);
|
|
36
44
|
}
|
|
37
45
|
}
|
|
38
46
|
return top_level_rows.map(r => r.data);
|
|
39
47
|
}
|
|
40
|
-
function assign_children(row,
|
|
41
|
-
const my_children =
|
|
42
|
-
if (my_children.length > 0) {
|
|
48
|
+
function assign_children(row, children_by_parent) {
|
|
49
|
+
const my_children = row.self == null ? undefined : children_by_parent.get(String(row.self));
|
|
50
|
+
if (my_children && my_children.length > 0) {
|
|
43
51
|
//find children of my children:
|
|
44
52
|
for (let index = 0; index < my_children.length; index++) {
|
|
45
53
|
const child = my_children[index];
|
|
46
|
-
assign_children(child,
|
|
54
|
+
assign_children(child, children_by_parent);
|
|
47
55
|
}
|
|
48
56
|
row.data.__children = my_children.map(r => r.data);
|
|
49
57
|
} else if (!Array.isArray(row.data.__children) || row.data.__children.length == 0) row.data.__children = undefined;
|
|
@@ -3,7 +3,10 @@ export type MakeWriteable<Type> = {
|
|
|
3
3
|
-readonly [Key in keyof Type]: Type[Key];
|
|
4
4
|
};
|
|
5
5
|
export type ModifyFields<T, R> = Omit<T, keyof R> & R;
|
|
6
|
-
export declare function ApplyDataSource(datasource: any, props: any
|
|
6
|
+
export declare function ApplyDataSource(datasource: any, props: any, remote?: {
|
|
7
|
+
remoteFilter?: boolean;
|
|
8
|
+
remoteSort?: boolean;
|
|
9
|
+
}): Promise<any>;
|
|
7
10
|
/**
|
|
8
11
|
* merges together all different props for columns
|
|
9
12
|
* to build a single final column data array
|
|
@@ -25,13 +25,17 @@ const defaultColumnOptions = {
|
|
|
25
25
|
lockable: false,
|
|
26
26
|
editable: false
|
|
27
27
|
};
|
|
28
|
-
async function ApplyDataSource(datasource, props) {
|
|
28
|
+
async function ApplyDataSource(datasource, props, remote = {}) {
|
|
29
29
|
let result_data = undefined;
|
|
30
30
|
let isUsingCache = false;
|
|
31
|
+
//filter/sort are only part of the key when they are sent to a remote dataSource,
|
|
32
|
+
//local filtering/sorting keeps reusing the cached rows
|
|
31
33
|
const cacheInfo = {
|
|
32
34
|
ds: datasource,
|
|
33
35
|
skip: props.skip,
|
|
34
|
-
limit: props.limit
|
|
36
|
+
limit: props.limit,
|
|
37
|
+
filterValue: remote.remoteFilter ? props.filterValue : undefined,
|
|
38
|
+
sortInfo: remote.remoteSort ? props.sortInfo : undefined
|
|
35
39
|
};
|
|
36
40
|
//check if we can used cached data
|
|
37
41
|
//if the datasource is changed since last render, we should invalidate cache
|
|
@@ -284,7 +288,10 @@ function get_default_key() {
|
|
|
284
288
|
}
|
|
285
289
|
//check if two cache objects are the same
|
|
286
290
|
function validateCache(current, old, looseCheck = false) {
|
|
287
|
-
|
|
291
|
+
//deep compare skip/limit/filterValue/sortInfo, array order matters (sort priority)
|
|
292
|
+
if (!old || !(0, _object.object_equals)(current, old, {
|
|
293
|
+
strictArrayCheck: true
|
|
294
|
+
})) return false;
|
|
288
295
|
if (looseCheck) return true;
|
|
289
296
|
if (current.ds != old.ds) return false;
|
|
290
297
|
return true;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { AzGridProps, LooseColumnDefinition } from '../types/types';
|
|
2
|
-
export declare function useColumnData(inputOrProps: undefined | any[] | LooseColumnDefinition[] | AzGridProps):
|
|
2
|
+
export declare function useColumnData(inputOrProps: undefined | any[] | LooseColumnDefinition[] | AzGridProps): any[];
|
|
@@ -7,18 +7,14 @@ exports.useColumnData = useColumnData;
|
|
|
7
7
|
var _react = _interopRequireDefault(require("react"));
|
|
8
8
|
var _func_grid = require("../func/func_grid");
|
|
9
9
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
const EMPTY_COLUMNS = [];
|
|
10
11
|
function useColumnData(inputOrProps) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
function useThisColumnData(cols) {
|
|
12
|
+
// one useMemo for every input kind, so switching between them keeps the hook order
|
|
13
|
+
const isProps = inputOrProps != null && !Array.isArray(inputOrProps);
|
|
14
|
+
const props = isProps ? inputOrProps : {};
|
|
15
|
+
const deps = isProps ? [props.columns, props.leftColumns, props.rightColumns, props.editableColumns, props.columnExtensions, props.customColumns] : [inputOrProps, null, null, null, null, null];
|
|
16
16
|
return _react.default.useMemo(() => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
function usePropsColumnData(props) {
|
|
21
|
-
return _react.default.useMemo(() => {
|
|
22
|
-
return (0, _func_grid.applyColumnData)(props);
|
|
23
|
-
}, [props.columns, props.leftColumns, props.rightColumns, props.editableColumns, props.columnExtensions, props.customColumns]);
|
|
17
|
+
if (inputOrProps == null) return EMPTY_COLUMNS;
|
|
18
|
+
return (0, _func_grid.applyColumnData)(inputOrProps);
|
|
19
|
+
}, [isProps, ...deps]);
|
|
24
20
|
}
|
|
@@ -8,14 +8,25 @@ var _react = _interopRequireDefault(require("react"));
|
|
|
8
8
|
var _func_grid = require("../func/func_grid");
|
|
9
9
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
10
|
function useDataSource(ds, props) {
|
|
11
|
+
var _props$gridOptions, _props$gridOptions2;
|
|
11
12
|
const cached_data = _react.default.useRef();
|
|
12
13
|
const last_cache_info = _react.default.useRef();
|
|
14
|
+
// filter/sort only change the result when the grid sends them to the dataSource
|
|
15
|
+
const remoteFilter = !!(props !== null && props !== void 0 && (_props$gridOptions = props.gridOptions) !== null && _props$gridOptions !== void 0 && _props$gridOptions.remoteFilter);
|
|
16
|
+
const remoteSort = !!(props !== null && props !== void 0 && (_props$gridOptions2 = props.gridOptions) !== null && _props$gridOptions2 !== void 0 && _props$gridOptions2.remoteSort);
|
|
13
17
|
return _react.default.useCallback(async dt => {
|
|
14
|
-
|
|
18
|
+
const params = {
|
|
15
19
|
skip: dt === null || dt === void 0 ? void 0 : dt.skip,
|
|
16
20
|
limit: dt === null || dt === void 0 ? void 0 : dt.limit,
|
|
21
|
+
filterValue: dt === null || dt === void 0 ? void 0 : dt.filterValue,
|
|
22
|
+
sortInfo: dt === null || dt === void 0 ? void 0 : dt.sortInfo,
|
|
23
|
+
groupBy: dt === null || dt === void 0 ? void 0 : dt.groupBy,
|
|
17
24
|
cached_data: cached_data,
|
|
18
25
|
last_cache_info: last_cache_info
|
|
26
|
+
};
|
|
27
|
+
return await (0, _func_grid.ApplyDataSource)(ds, params, {
|
|
28
|
+
remoteFilter,
|
|
29
|
+
remoteSort
|
|
19
30
|
});
|
|
20
|
-
}, [ds]);
|
|
31
|
+
}, [ds, remoteFilter, remoteSort]);
|
|
21
32
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { DataGridWrapperProps, GridType } from '../types/types';
|
|
2
2
|
export declare function useGridEvents(grid: GridType, props: DataGridWrapperProps): {
|
|
3
3
|
onRowClick: (rowProps: any, event: any) => void | undefined;
|
|
4
|
+
onRenderLoadMask: (maskProps: {
|
|
5
|
+
visible?: boolean;
|
|
6
|
+
}) => void;
|
|
4
7
|
onRowContextMenu: (rowProps: any, event: any) => boolean;
|
|
5
8
|
onRenderRow: (rowProps: any) => void;
|
|
6
9
|
update_menuRow: (r?: any, el?: any) => void;
|
|
@@ -24,6 +24,9 @@ function useGridMenuRow() {
|
|
|
24
24
|
}
|
|
25
25
|
function useGridEvents(grid, props) {
|
|
26
26
|
const click_data = _react.default.useRef(null);
|
|
27
|
+
// latest props, so the callbacks below stay stable and don't re-render the grid
|
|
28
|
+
const latestProps = _react.default.useRef(props);
|
|
29
|
+
latestProps.current = props;
|
|
27
30
|
const {
|
|
28
31
|
update_menuRow,
|
|
29
32
|
menuAnchorEl,
|
|
@@ -52,18 +55,22 @@ function useGridEvents(grid, props) {
|
|
|
52
55
|
/* events */
|
|
53
56
|
/* -------------------------------------------------------------------------- */
|
|
54
57
|
const onRowClick = _react.default.useCallback((rowProps, event) => {
|
|
58
|
+
const {
|
|
59
|
+
onRowClick,
|
|
60
|
+
onRowDoubleClick
|
|
61
|
+
} = latestProps.current;
|
|
55
62
|
const nowDate = Date.now();
|
|
56
63
|
const lastclick = click_data.current[(0, _func_grid.get_row_id)(rowProps)];
|
|
57
64
|
if (lastclick) {
|
|
58
65
|
const diffTime = Math.abs(nowDate - lastclick);
|
|
59
66
|
if (diffTime < 400) {
|
|
60
67
|
click_data.current[(0, _func_grid.get_row_id)(rowProps)] = null;
|
|
61
|
-
return
|
|
68
|
+
return onRowDoubleClick && onRowDoubleClick(rowProps.rowIndex, rowProps.data);
|
|
62
69
|
}
|
|
63
70
|
}
|
|
64
71
|
click_data.current[(0, _func_grid.get_row_id)(rowProps)] = nowDate;
|
|
65
|
-
return
|
|
66
|
-
}, [
|
|
72
|
+
return onRowClick && onRowClick(rowProps.rowIndex, rowProps.data);
|
|
73
|
+
}, []);
|
|
67
74
|
_react.default.useEffect(() => {
|
|
68
75
|
click_data.current = {};
|
|
69
76
|
}, [props.dataSource]);
|
|
@@ -81,25 +88,24 @@ function useGridEvents(grid, props) {
|
|
|
81
88
|
}, []);
|
|
82
89
|
/* -------------------------------------------------------------------------- */
|
|
83
90
|
/* ------------------------------ Accessibility ----------------------------- */
|
|
84
|
-
const latestProps = _react.default.useRef(props);
|
|
85
|
-
latestProps.current = props;
|
|
86
91
|
const rootSyncFrame = _react.default.useRef(0);
|
|
87
92
|
// last applied root values, so row renders (e.g. while scrolling) don't re-apply them
|
|
88
93
|
const lastRoot = _react.default.useRef({
|
|
89
94
|
el: null,
|
|
90
|
-
key: ''
|
|
95
|
+
key: '',
|
|
96
|
+
busy: false
|
|
91
97
|
});
|
|
92
98
|
const getRootOptions = () => ({
|
|
93
99
|
ariaLabel: latestProps.current.ariaLabel,
|
|
94
100
|
editable: !!latestProps.current.editable
|
|
95
101
|
});
|
|
96
102
|
// root attributes are set on the DOM node, batched to once per frame
|
|
97
|
-
const scheduleRootSync = _react.default.useCallback(() => {
|
|
103
|
+
const scheduleRootSync = _react.default.useCallback((force = false) => {
|
|
98
104
|
var _latestProps$current$;
|
|
99
105
|
if (rootSyncFrame.current || typeof requestAnimationFrame === 'undefined') return;
|
|
100
106
|
const grid = (_latestProps$current$ = latestProps.current.liveGridRef) === null || _latestProps$current$ === void 0 || (_latestProps$current$ = _latestProps$current$.current) === null || _latestProps$current$ === void 0 ? void 0 : _latestProps$current$.current;
|
|
101
107
|
const key = (0, _func_a11y.get_root_a11y_key)(grid, getRootOptions());
|
|
102
|
-
if (key && key === lastRoot.current.key && (0, _func_a11y.get_grid_root)(grid) === lastRoot.current.el) return;
|
|
108
|
+
if (!force && key && key === lastRoot.current.key && (0, _func_a11y.get_grid_root)(grid) === lastRoot.current.el) return;
|
|
103
109
|
rootSyncFrame.current = requestAnimationFrame(() => {
|
|
104
110
|
var _latestProps$current$2;
|
|
105
111
|
rootSyncFrame.current = 0;
|
|
@@ -108,7 +114,8 @@ function useGridEvents(grid, props) {
|
|
|
108
114
|
const el = (0, _func_a11y.apply_root_a11y)(liveGrid, options);
|
|
109
115
|
lastRoot.current = {
|
|
110
116
|
el,
|
|
111
|
-
key: el ? (0, _func_a11y.get_root_a11y_key)(liveGrid, options) : ''
|
|
117
|
+
key: el ? (0, _func_a11y.get_root_a11y_key)(liveGrid, options) : '',
|
|
118
|
+
busy: el ? (0, _func_a11y.is_grid_busy)(liveGrid) : false
|
|
112
119
|
};
|
|
113
120
|
});
|
|
114
121
|
}, []);
|
|
@@ -127,8 +134,13 @@ function useGridEvents(grid, props) {
|
|
|
127
134
|
(0, _func_a11y.apply_row_a11y)(rowProps, !!(liveGrid !== null && liveGrid !== void 0 && liveGrid.computedRowSelectionEnabled));
|
|
128
135
|
scheduleRootSync();
|
|
129
136
|
}, []);
|
|
137
|
+
// called by the grid on every render with the load mask state, keeps aria-busy in sync
|
|
138
|
+
const onRenderLoadMask = _react.default.useCallback(maskProps => {
|
|
139
|
+
if (!!(maskProps !== null && maskProps !== void 0 && maskProps.visible) !== lastRoot.current.busy) scheduleRootSync(true);
|
|
140
|
+
}, []);
|
|
130
141
|
return {
|
|
131
142
|
onRowClick,
|
|
143
|
+
onRenderLoadMask,
|
|
132
144
|
onRowContextMenu,
|
|
133
145
|
onRenderRow,
|
|
134
146
|
update_menuRow,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { DataGridWrapperProps
|
|
3
|
-
export declare function useGridSearch(
|
|
4
|
-
filteredData: any;
|
|
2
|
+
import { DataGridWrapperProps } from '../types/types';
|
|
3
|
+
export declare function useGridSearch(props: DataGridWrapperProps): {
|
|
4
|
+
filteredData: any[] | ((args: any) => Promise<any>);
|
|
5
5
|
element: React.JSX.Element;
|
|
6
6
|
};
|
|
@@ -8,51 +8,77 @@ var _react = _interopRequireDefault(require("react"));
|
|
|
8
8
|
var _lodash = _interopRequireDefault(require("lodash.debounce"));
|
|
9
9
|
var _object = require("@azrico/object");
|
|
10
10
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
|
-
|
|
11
|
+
const SEARCH_DELAY = 300;
|
|
12
|
+
function to_rows(result) {
|
|
13
|
+
return result && typeof result === 'object' ? result.data || result : result;
|
|
14
|
+
}
|
|
15
|
+
//false when the result is only a page of the data (remote pagination)
|
|
16
|
+
function is_complete(result) {
|
|
17
|
+
if (!result || typeof result !== 'object' || Array.isArray(result)) return true;
|
|
18
|
+
const loaded = Array.isArray(result.data) ? result.data.length : 0;
|
|
19
|
+
return !(result.count > loaded);
|
|
20
|
+
}
|
|
21
|
+
function useGridSearch(props) {
|
|
12
22
|
const [search, set_search] = _react.default.useState('');
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
23
|
+
// null shows the datasource itself, an array shows search results
|
|
24
|
+
const [searchResult, set_searchResult] = _react.default.useState(null);
|
|
25
|
+
const latestProps = _react.default.useRef(props);
|
|
26
|
+
latestProps.current = props;
|
|
27
|
+
// last result the grid loaded, reused by search instead of loading the data again
|
|
28
|
+
const loaded = _react.default.useRef(null);
|
|
29
|
+
const searchId = _react.default.useRef(0);
|
|
30
|
+
const trackedDataSource = _react.default.useCallback(async args => {
|
|
31
|
+
const result = await (0, _object.fn_eval)(props.dataSource, args);
|
|
32
|
+
loaded.current = {
|
|
33
|
+
ds: props.dataSource,
|
|
34
|
+
result
|
|
35
|
+
};
|
|
36
|
+
return result;
|
|
37
|
+
}, [props.dataSource]);
|
|
38
|
+
const get_search_rows = _react.default.useCallback(async () => {
|
|
39
|
+
const ds = latestProps.current.dataSource;
|
|
40
|
+
const last = loaded.current;
|
|
41
|
+
if (last && last.ds === ds && is_complete(last.result)) return to_rows(last.result);
|
|
42
|
+
return to_rows(await (0, _object.fn_eval)(ds));
|
|
43
|
+
}, []);
|
|
44
|
+
const filter_rows = _react.default.useCallback((rows, text) => {
|
|
45
|
+
var _gridRef$current;
|
|
46
|
+
const {
|
|
47
|
+
gridRef,
|
|
48
|
+
advancedFilterFields
|
|
49
|
+
} = latestProps.current;
|
|
50
|
+
const visibleColumns = (_gridRef$current = gridRef.current) === null || _gridRef$current === void 0 ? void 0 : _gridRef$current.visibleColumns;
|
|
51
|
+
const columns_to_search = visibleColumns ? (0, _object.array_intersection)(advancedFilterFields || [], visibleColumns.map(r => r.id)) : advancedFilterFields || [];
|
|
52
|
+
const lowerSearchText = text.toLowerCase().trim();
|
|
53
|
+
if (!lowerSearchText || columns_to_search.length === 0) return rows;
|
|
54
|
+
return rows.filter(p => {
|
|
55
|
+
for (let index = 0; index < columns_to_search.length; index++) {
|
|
56
|
+
const col = columns_to_search[index];
|
|
57
|
+
const v = (p[col] + '').toLowerCase(); //value of column
|
|
58
|
+
if (v && v.indexOf(lowerSearchText) != -1) {
|
|
59
|
+
//if one column is matching then the row is a match
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
37
62
|
}
|
|
38
|
-
|
|
39
|
-
set_filteredData(newData);
|
|
40
|
-
}, 1000), [grid]);
|
|
41
|
-
_react.default.useEffect(() => {
|
|
42
|
-
(0, _object.fn_eval)(props.dataSource).then(r => {
|
|
43
|
-
currentDS.current = typeof r === 'object' ? r.data || r : r;
|
|
44
|
-
searchIfNeeded();
|
|
63
|
+
return false;
|
|
45
64
|
});
|
|
46
|
-
}, [
|
|
65
|
+
}, []);
|
|
66
|
+
const run_search = _react.default.useMemo(() => (0, _lodash.default)(async text => {
|
|
67
|
+
const id = ++searchId.current;
|
|
68
|
+
const rows = await get_search_rows();
|
|
69
|
+
if (id !== searchId.current || !Array.isArray(rows)) return; //a newer search started
|
|
70
|
+
set_searchResult(filter_rows(rows, text));
|
|
71
|
+
}, SEARCH_DELAY), []);
|
|
72
|
+
_react.default.useEffect(() => () => run_search.cancel(), [run_search]);
|
|
47
73
|
_react.default.useEffect(() => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
74
|
+
if (search) {
|
|
75
|
+
run_search(search);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
run_search.cancel();
|
|
79
|
+
searchId.current++;
|
|
80
|
+
set_searchResult(null);
|
|
81
|
+
}, [search, props.dataSource]);
|
|
56
82
|
const element = _react.default.createElement(_react.default.Fragment, null, _react.default.createElement("form", {
|
|
57
83
|
className: 'azgrid-searcharea'
|
|
58
84
|
}, _react.default.createElement("label", null, "Search", _react.default.createElement("input", {
|
|
@@ -62,7 +88,7 @@ function useGridSearch(grid, props) {
|
|
|
62
88
|
onChange: e => set_search(e.target.value)
|
|
63
89
|
}))));
|
|
64
90
|
return {
|
|
65
|
-
filteredData,
|
|
91
|
+
filteredData: searchResult !== null && searchResult !== void 0 ? searchResult : trackedDataSource,
|
|
66
92
|
element
|
|
67
93
|
};
|
|
68
94
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ModifyFields } from '../func/func_grid';
|
|
2
2
|
import { ConvertableToMenuItem } from '@azrico/controls/context-menu';
|
|
3
3
|
import React from 'react';
|
|
4
|
-
import { TypeCellSelection, TypeColumn, TypeDataGridProps, TypeDataSource, TypeEditInfo, TypeFilterTypes, TypeFilterValue, TypeRowDetailsInfo, TypeRowProps, TypeRowSelection, TypeComputedProps } from '@inovua/reactdatagrid-community/types';
|
|
4
|
+
import { TypeCellSelection, TypeColumn, TypeDataGridProps, TypeDataSource, TypeEditInfo, TypeFilterTypes, TypeFilterValue, TypeRowDetailsInfo, TypeRowProps, TypeRowSelection, TypeComputedProps, TypeSortInfo, TypeGroupBy } from '@inovua/reactdatagrid-community/types';
|
|
5
5
|
import { TypeOnSelectionChangeArg } from '@inovua/reactdatagrid-community/types/TypeDataGridProps';
|
|
6
6
|
export type ColumnDefinition = TypeColumn;
|
|
7
7
|
export type CellDefinition = any;
|
|
@@ -44,9 +44,21 @@ export type AzGridOptions = Partial<TypeDataGridProps> & {
|
|
|
44
44
|
[key: string]: any;
|
|
45
45
|
};
|
|
46
46
|
};
|
|
47
|
+
/** arguments passed to a dataSource function */
|
|
48
|
+
export type AzDataSourceParams = {
|
|
49
|
+
skip?: number;
|
|
50
|
+
limit?: number;
|
|
51
|
+
/** current header filters, filter.value is an array of selected ids for a multi-select SelectFilter */
|
|
52
|
+
filterValue?: TypeFilterValue;
|
|
53
|
+
sortInfo?: TypeSortInfo;
|
|
54
|
+
groupBy?: TypeGroupBy;
|
|
55
|
+
cached_data: React.MutableRefObject<any>;
|
|
56
|
+
last_cache_info: React.MutableRefObject<any>;
|
|
57
|
+
};
|
|
58
|
+
export type AzDataSourceFunc = (args: AzDataSourceParams) => any[] | Promise<any[] | any>;
|
|
47
59
|
export type AzGridProps = {
|
|
48
|
-
dataSource?: any[] |
|
|
49
|
-
details_dataSource?: any[] |
|
|
60
|
+
dataSource?: any[] | AzDataSourceFunc;
|
|
61
|
+
details_dataSource?: any[] | AzDataSourceFunc;
|
|
50
62
|
details_columns?: LooseColumnDefinition[];
|
|
51
63
|
details_filter?: FilterValues;
|
|
52
64
|
licenseKey?: string;
|