@azrico/reactgrid 1.6.11 → 1.6.13

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.
@@ -1,371 +1,405 @@
1
- import '@inovua/reactdatagrid-enterprise/index.css';
2
- import '../themes/base_styles.css';
3
- import '../themes/grid.css';
4
- import { get_default_key, get_row_id } from '../func/func_grid';
5
- import { ContextMenu } from '@azrico/controls/context-menu';
6
- import React from 'react';
7
-
8
- import ReactDataGrid from '@inovua/reactdatagrid-enterprise';
9
- import clsx from 'clsx';
10
- import { useComponentSize } from 'react-use-size';
11
-
12
- import { AzGridOptions, AzGridProps, DataGridWrapperProps } from '../types/types';
13
- import { useGridEvents } from '../hooks/useGridEvents';
14
- import { useColumnData } from '../hooks/useColumnData';
15
- import { useDataSource } from '../hooks/useDatasource';
16
- import { useGridSearch } from '../hooks/useGridSearch';
17
- import { apply_column_a11y } from '../func/func_a11y';
18
- import { id as rowIndexColumnId } from '@inovua/reactdatagrid-community/normalizeColumns/defaultRowIndexColumnId';
19
- import { id as checkboxColumnId } from '@inovua/reactdatagrid-community/normalizeColumns/defaultCheckColumnId';
20
- /* -------------------------------------------------------------------------- */
21
-
22
- /* -------------------------------------------------------------------------- */
23
-
24
- const defaultOptions: AzGridOptions = {
25
- //filterTypes: defaultfilterTypes,
26
- remoteFilter: false,
27
- remoteSort: false,
28
- editStartEvent: 'click',
29
- rowReorderColumn: false,
30
- resizable: true,
31
- columnUserSelect: true,
32
- rowIndexColumn: true,
33
- rowHeight: 35,
34
- };
35
- const forcedOptions: AzGridOptions = {
36
- idProperty: '__table_id',
37
- nodesProperty: '__children',
38
- theme: 'default-light',
39
- };
40
-
41
- const dynamic_option_names = ['selected', 'cellSelection', 'loading', 'limit', 'skip'];
42
- // consumer callbacks forwarded to the grid; wrapped so a new function doesn't re-render the grid
43
- const callback_option_names = [
44
- 'onSkipChange',
45
- 'onLimitChange',
46
- 'onEditComplete',
47
- 'onSelectionChange',
48
- 'onCellSelectionChange',
49
- ];
50
- // props DataGridCore renders from, other props don't need to re-render the grid
51
- const core_prop_names = [
52
- 'className',
53
- 'static_gridOptions',
54
- 'dynamic_gridOptions',
55
- 'columns',
56
- 'dataSource',
57
- 'gridRef',
58
- 'liveGridRef',
59
- 'allowChildRows',
60
- 'theme',
61
- 'dark',
62
- 'children',
63
- ];
64
- /* -------------------------------------------------------------------------- */
65
- export function AzGrid(props: AzGridProps) {
66
- const gridRefBackup = React.useRef<any>(null);
67
- const gridRef = props.gridRef || gridRefBackup;
68
- const liveGridRef = React.useRef<any>(null);
69
- const latestProps = React.useRef(props);
70
- latestProps.current = props;
71
-
72
- /* -------------------------------------------------------------------------- */
73
- /* Columns */
74
- /* -------------------------------------------------------------------------- */
75
- const cached_columns = useColumnData(props);
76
- const dataSource = useDataSource(props.dataSource, props);
77
- const a11y_columns = React.useMemo(
78
- () => cached_columns.map((col) => apply_column_a11y(col, { gridEditable: !!props.editable })),
79
- [cached_columns, props.editable]
80
- );
81
- /* -------------------------------------------------------------------------- */
82
- /* Row changes */
83
- /* -------------------------------------------------------------------------- */
84
-
85
- const base_gridOptions = React.useMemo<AzGridOptions>(() => {
86
- const firstcolumn = cached_columns[0];
87
- const licenseKey = props.licenseKey || get_default_key();
88
- // call the latest consumer callback, only passed when the consumer gave one
89
- const events: AzGridOptions = {};
90
- callback_option_names.forEach((name) => {
91
- if (props[name])
92
- events[name] = (...args: any[]) => latestProps.current[name]?.(...args);
93
- });
94
- const extra_ops: AzGridOptions = {
95
- licenseKey: licenseKey,
96
- editable: props.editable as any, //bug in types of the plugin
97
- treeColumn: props.allowChildRows ? firstcolumn.name : undefined,
98
- renderRowDetails: props.RowDetail,
99
- };
100
- return { ...defaultOptions, ...events, ...extra_ops };
101
- }, [
102
- cached_columns,
103
- props.allowChildRows,
104
- props.editable,
105
- props.RowDetail,
106
- props.licenseKey,
107
- ...callback_option_names.map((name) => !!props[name]),
108
- ]);
109
-
110
- const static_gridOptions = React.useMemo<AzGridOptions>(() => {
111
- const finalres = { ...base_gridOptions, ...props.gridOptions, ...forcedOptions };
112
-
113
- //append filter types instead of replacing it
114
- if (finalres.filterTypes)
115
- finalres.filterTypes = Object.assign(
116
- {},
117
- ReactDataGrid.defaultProps.filterTypes,
118
- finalres.filterTypes
119
- );
120
-
121
- return finalres;
122
- }, [props.gridOptions, base_gridOptions, forcedOptions]);
123
-
124
- const dynamic_gridOptions = React.useMemo<AzGridOptions>(
125
- () => {
126
- const res = {};
127
- dynamic_option_names.map((r) => {
128
- res[r] = props[r];
129
- });
130
- return res;
131
- },
132
- dynamic_option_names.map((r) => props[r])
133
- );
134
-
135
- return (
136
- <DataGridEventsWrapper
137
- {...props}
138
- gridRef={gridRef}
139
- liveGridRef={liveGridRef}
140
- static_gridOptions={static_gridOptions}
141
- dynamic_gridOptions={dynamic_gridOptions}
142
- columns={a11y_columns}
143
- dataSource={dataSource}
144
- highlightedRow={props.highlightedRow}
145
- />
146
- );
147
- }
148
-
149
- /* -------------------------------------------------------------------------- */
150
- /**
151
- * Wrapper for menu events
152
- * @param props
153
- * @returns
154
- */
155
- function DataGridEventsWrapper(props: DataGridWrapperProps) {
156
- const themeClass = `azgrid-theme-${props.theme ?? (props.dark ? 'dark' : 'light')}`;
157
- /* -------------------------------------------------------------------------- */
158
- const {
159
- onRowClick,
160
- onRowContextMenu,
161
- onRenderRow,
162
- onRenderLoadMask,
163
- update_menuRow,
164
- menuAnchorEl,
165
- menuRow,
166
- } = useGridEvents(props.gridRef.current, props);
167
- const menuRowId =
168
- menuAnchorEl && !props.hideContextMenu && props.contextMenuItems
169
- ? get_row_id(menuRow)
170
- : undefined;
171
- const consumerRowClassName = props.static_gridOptions?.rowClassName;
172
- const rowClassName = React.useCallback(
173
- (rowProps) => clsx(
174
- typeof consumerRowClassName === 'function'
175
- ? consumerRowClassName(rowProps)
176
- : consumerRowClassName,
177
- menuRowId != null && get_row_id(rowProps.data) === menuRowId && 'azgrid-row--menu-open'
178
- ),
179
- [consumerRowClassName, menuRowId]
180
- );
181
- /* -------------------------------------------------------------------------- */
182
- /**
183
- * Merge click events into grid options
184
- */
185
- const static_gridOptions = React.useMemo<AzGridOptions>(() => {
186
- const opts: any = props.static_gridOptions || {};
187
- const events: AzGridOptions = {
188
- onRowClick: onRowClick,
189
- onRowContextMenu: onRowContextMenu,
190
- };
191
-
192
- // internal row attributes first, consumer's onRenderRow last so it can override them
193
- const consumerOnRenderRow = opts.onRenderRow;
194
- const renderProps: any = {
195
- rowClassName,
196
- onRenderRow: consumerOnRenderRow
197
- ? (rowProps) => {
198
- onRenderRow(rowProps);
199
- consumerOnRenderRow(rowProps);
200
- }
201
- : onRenderRow,
202
- // track loading for aria-busy, the consumer's renderLoadMask (if any) still renders the mask
203
- renderLoadMask: (maskProps) => {
204
- onRenderLoadMask(maskProps);
205
- return opts.renderLoadMask ? opts.renderLoadMask(maskProps) : undefined;
206
- },
207
- };
208
-
209
- const gridEditable = !!props.editable;
210
- const a11yProps: any = {
211
- headerProps: { role: 'row', 'aria-rowindex': 1, ...opts.headerProps },
212
- rowIndexColumn: apply_column_a11y(
213
- typeof opts.rowIndexColumn === 'object' ? opts.rowIndexColumn : {},
214
- { role: 'rowheader', gridEditable, id: rowIndexColumnId }
215
- ),
216
- };
217
- if (opts.checkboxColumn)
218
- a11yProps.checkboxColumn = apply_column_a11y(
219
- typeof opts.checkboxColumn === 'object' ? opts.checkboxColumn : {},
220
- { gridEditable, markReadonly: false, id: checkboxColumnId }
221
- );
222
-
223
- return {
224
- ...opts,
225
- ...events,
226
- ...renderProps,
227
- ...a11yProps,
228
- };
229
- }, [
230
- props.static_gridOptions,
231
- props.editable,
232
- onRowClick,
233
- onRowContextMenu,
234
- onRenderRow,
235
- onRenderLoadMask,
236
- rowClassName,
237
- ]);
238
-
239
- /* -------------------------------------------------------------------------- */
240
- // The menu is portaled to <body>, so it carries the theme class itself to get the theme tokens.
241
- return (
242
- <div className={clsx('azgrid-scope azgrid-flexed azgrid-flexlayout', themeClass)}>
243
- {!props.hideContextMenu && props.contextMenuItems && (
244
- <ContextMenu
245
- classname={clsx('azgrid-context-menu', themeClass, props.contextMenuClassName)}
246
- menuAnchorEl={menuAnchorEl}
247
- menuRow={menuRow}
248
- close={update_menuRow}
249
- dontAutoClose={props.dontAutoCloseContextMenu ?? false}
250
- escapeClosesContextMenu={props.escapeClosesContextMenu ?? false}
251
- menu_items={props.contextMenuItems as any}
252
- />
253
- )}
254
- {props.details_dataSource ? (
255
- <DataGridDetailsWrapper {...props} static_gridOptions={static_gridOptions} />
256
- ) : (
257
- <DataGridSizeWrapper {...props} static_gridOptions={static_gridOptions} />
258
- )}
259
- </div>
260
- );
261
- }
262
-
263
- function DataGridDetailsWrapper(props: DataGridWrapperProps) {
264
- const cached_details_columns = useColumnData(props.details_columns);
265
- const details_dataSource = useDataSource(props.details_dataSource, props);
266
- const renderDetailsGrid = ({ data }) => {
267
- return (
268
- <ReactDataGrid
269
- theme="default-light"
270
- className={clsx('azgrid', `azgrid-theme-${props.theme ?? (props.dark ? 'dark' : 'light')}`)}
271
- defaultFilterValue={props.details_filter}
272
- dataSource={details_dataSource}
273
- columns={cached_details_columns}
274
- />
275
- );
276
- };
277
-
278
- /**
279
- * Merge details into grid
280
- */
281
- const static_gridOptions = React.useMemo<AzGridOptions>(() => {
282
- const finalresult = props.static_gridOptions || {};
283
- finalresult['renderDetailsGrid'] = renderDetailsGrid;
284
- return finalresult;
285
- }, [props.static_gridOptions, props.theme, props.dark]);
286
-
287
- return <DataGridSizeWrapper {...props} static_gridOptions={static_gridOptions} />;
288
- }
289
-
290
- function DataGridSizeWrapper(props: DataGridWrapperProps) {
291
- if (props.delayedSize) {
292
- return <DataGridDelayedSizeWrapper {...props} />;
293
- } else {
294
- return <DataGridNormalSizeWrapper {...props} />;
295
- }
296
- }
297
-
298
- /* -------------------------------------------------------------------------- */
299
- function DataGridNormalSizeWrapper(props: DataGridWrapperProps) {
300
- return props.advancedFilterFields ? (
301
- <DataGridSearchWrapper {...props} />
302
- ) : (
303
- <DataGridCore {...props} />
304
- );
305
- }
306
- function DataGridDelayedSizeWrapper(props: DataGridWrapperProps) {
307
- const { ref, height, width } = useComponentSize();
308
- return (
309
- <div ref={ref} className={'azgrid-filler azgrid-nooverflow '}>
310
- <div
311
- className={'azgrid-delayedresize azgrid-flexlayout'}
312
- style={{ height: height, width: width }}
313
- >
314
- {props.advancedFilterFields ? (
315
- <DataGridSearchWrapper {...props} />
316
- ) : (
317
- <DataGridCore {...props} />
318
- )}
319
- </div>
320
- </div>
321
- );
322
- }
323
- function DataGridSearchWrapper(props: DataGridWrapperProps) {
324
- const { element, filteredData } = useGridSearch(props);
325
-
326
- return (
327
- <div className={'azgrid-flexed azgrid-flexlayout azgrid-nooverflow'}>
328
- {element}
329
- <DataGridCore {...props} dataSource={filteredData} />
330
- </div>
331
- );
332
- }
333
- const DataGridCore = React.memo(DataGridCoreView, (prev, next) =>
334
- core_prop_names.every((name) => prev[name] === next[name])
335
- );
336
- function DataGridCoreView(props: DataGridWrapperProps) {
337
- const { gridRef, liveGridRef } = props;
338
- const handle = React.useCallback(
339
- (ref) => {
340
- if (ref) gridRef.current = ref.current as any;
341
- if (liveGridRef) liveGridRef.current = ref as any;
342
- },
343
- [gridRef, liveGridRef]
344
- );
345
- return (
346
- <div className={clsx(props.className, 'azgrid-flexed', 'azgrid-flexlayout')}>
347
- <ReactDataGrid
348
- {...props.static_gridOptions}
349
- {...props.dynamic_gridOptions}
350
- rowIndexColumn={props.static_gridOptions.rowIndexColumn || true}
351
- handle={handle}
352
- theme="default-light"
353
- className={clsx(
354
- 'azgrid azgrid-flexed',
355
- props.allowChildRows && 'azgrid-tree',
356
- `azgrid-theme-${props.theme ?? (props.dark ? 'dark' : 'light')}`
357
- )}
358
- columns={props.columns}
359
- dataSource={props.dataSource}
360
- />
361
- {props.children}
362
- </div>
363
- );
364
- }
365
- /* -------------------------------------------------------------------------- */
366
- /* -------------------------------------------------------------------------- */
367
- /* -------------------------------------------------------------------------- */
368
- /* -------------------------------------------------------------------------- */
369
-
370
- /* -------------------------------------------------------------------------- */
371
- export default AzGrid;
1
+ import '@inovua/reactdatagrid-enterprise/index.css';
2
+ import '../themes/base_styles.css';
3
+ import '../themes/grid.css';
4
+ import { get_default_key, get_row_id } from '../func/func_grid';
5
+ import { ContextMenu } from '@azrico/controls/context-menu';
6
+ import React from 'react';
7
+
8
+ import ReactDataGrid from '@inovua/reactdatagrid-enterprise';
9
+ import clsx from 'clsx';
10
+ import { useComponentSize } from 'react-use-size';
11
+
12
+ import { AzGridOptions, AzGridProps, DataGridWrapperProps } from '../types/types';
13
+ import { useGridEvents } from '../hooks/useGridEvents';
14
+ import { useColumnData } from '../hooks/useColumnData';
15
+ import { useDataSource } from '../hooks/useDatasource';
16
+ import { useGridSearch } from '../hooks/useGridSearch';
17
+ import { apply_column_a11y } from '../func/func_a11y';
18
+ import {
19
+ apply_column_sizes,
20
+ ColumnSizes,
21
+ isValidWidth,
22
+ loadColumnSizes,
23
+ saveColumnSizes,
24
+ } from '../func/func_colsizes';
25
+ import debounce from 'lodash.debounce';
26
+ import { id as rowIndexColumnId } from '@inovua/reactdatagrid-community/normalizeColumns/defaultRowIndexColumnId';
27
+ import { id as checkboxColumnId } from '@inovua/reactdatagrid-community/normalizeColumns/defaultCheckColumnId';
28
+ /* -------------------------------------------------------------------------- */
29
+
30
+ /* -------------------------------------------------------------------------- */
31
+
32
+ const defaultOptions: AzGridOptions = {
33
+ //filterTypes: defaultfilterTypes,
34
+ remoteFilter: false,
35
+ remoteSort: false,
36
+ editStartEvent: 'click',
37
+ rowReorderColumn: false,
38
+ resizable: true,
39
+ columnUserSelect: true,
40
+ rowIndexColumn: true,
41
+ rowHeight: 35,
42
+ };
43
+ const forcedOptions: AzGridOptions = {
44
+ idProperty: '__table_id',
45
+ nodesProperty: '__children',
46
+ theme: 'default-light',
47
+ };
48
+
49
+ const dynamic_option_names = ['selected', 'cellSelection', 'loading', 'limit', 'skip'];
50
+ // consumer callbacks forwarded to the grid; wrapped so a new function doesn't re-render the grid
51
+ const callback_option_names = [
52
+ 'onSkipChange',
53
+ 'onLimitChange',
54
+ 'onEditComplete',
55
+ 'onSelectionChange',
56
+ 'onCellSelectionChange',
57
+ ];
58
+ // props DataGridCore renders from, other props don't need to re-render the grid
59
+ const core_prop_names = [
60
+ 'className',
61
+ 'static_gridOptions',
62
+ 'dynamic_gridOptions',
63
+ 'columns',
64
+ 'dataSource',
65
+ 'gridRef',
66
+ 'liveGridRef',
67
+ 'allowChildRows',
68
+ 'theme',
69
+ 'dark',
70
+ 'children',
71
+ ];
72
+ /* -------------------------------------------------------------------------- */
73
+ export function AzGrid(props: AzGridProps) {
74
+ const gridRefBackup = React.useRef<any>(null);
75
+ const gridRef = props.gridRef || gridRefBackup;
76
+ const liveGridRef = React.useRef<any>(null);
77
+ const latestProps = React.useRef(props);
78
+ latestProps.current = props;
79
+
80
+ /* -------------------------------------------------------------------------- */
81
+ /* Columns */
82
+ /* -------------------------------------------------------------------------- */
83
+ const data_columns = useColumnData(props);
84
+ const dataSource = useDataSource(props.dataSource, props);
85
+ // saved widths are read once per grid id, resizing only updates this map so the columns aren't re-created mid-drag
86
+ const savedSizes = React.useRef<{ gridId?: string; sizes: ColumnSizes }>({ sizes: {} });
87
+ const saveSizesDebounced = React.useMemo(
88
+ () =>
89
+ props.gridId
90
+ ? debounce(() => saveColumnSizes(props.gridId!, savedSizes.current.sizes), 300)
91
+ : null,
92
+ [props.gridId]
93
+ );
94
+ React.useEffect(() => () => saveSizesDebounced?.flush(), [saveSizesDebounced]);
95
+ const cached_columns = React.useMemo(() => {
96
+ if (!props.gridId) return data_columns;
97
+ if (savedSizes.current.gridId !== props.gridId)
98
+ savedSizes.current = { gridId: props.gridId, sizes: loadColumnSizes(props.gridId) };
99
+ return apply_column_sizes(data_columns, savedSizes.current.sizes);
100
+ }, [data_columns, props.gridId]);
101
+ const a11y_columns = React.useMemo(
102
+ () => cached_columns.map((col) => apply_column_a11y(col, { gridEditable: !!props.editable })),
103
+ [cached_columns, props.editable]
104
+ );
105
+ /* -------------------------------------------------------------------------- */
106
+ /* Row changes */
107
+ /* -------------------------------------------------------------------------- */
108
+
109
+ const base_gridOptions = React.useMemo<AzGridOptions>(() => {
110
+ const firstcolumn = cached_columns[0];
111
+ const licenseKey = props.licenseKey || get_default_key();
112
+ // call the latest consumer callback, only passed when the consumer gave one
113
+ const events: AzGridOptions = {};
114
+ callback_option_names.forEach((name) => {
115
+ if (props[name])
116
+ events[name] = (...args: any[]) => latestProps.current[name]?.(...args);
117
+ });
118
+ const extra_ops: AzGridOptions = {
119
+ licenseKey: licenseKey,
120
+ editable: props.editable as any, //bug in types of the plugin
121
+ treeColumn: props.allowChildRows ? firstcolumn.name : undefined,
122
+ renderRowDetails: props.RowDetail,
123
+ };
124
+ return { ...defaultOptions, ...events, ...extra_ops };
125
+ }, [
126
+ cached_columns,
127
+ props.allowChildRows,
128
+ props.editable,
129
+ props.RowDetail,
130
+ props.licenseKey,
131
+ ...callback_option_names.map((name) => !!props[name]),
132
+ ]);
133
+
134
+ const static_gridOptions = React.useMemo<AzGridOptions>(() => {
135
+ const finalres = { ...base_gridOptions, ...props.gridOptions, ...forcedOptions };
136
+
137
+ //append filter types instead of replacing it
138
+ if (finalres.filterTypes)
139
+ finalres.filterTypes = Object.assign(
140
+ {},
141
+ ReactDataGrid.defaultProps.filterTypes,
142
+ finalres.filterTypes
143
+ );
144
+
145
+ if (saveSizesDebounced)
146
+ finalres.onColumnResize = (info, ...rest) => {
147
+ const name = info.column.name ?? info.column.id;
148
+ if (name != null && isValidWidth(info.width)) {
149
+ savedSizes.current.sizes[name] = info.width;
150
+ saveSizesDebounced();
151
+ }
152
+ latestProps.current.gridOptions?.onColumnResize?.(info, ...rest);
153
+ };
154
+
155
+ return finalres;
156
+ }, [props.gridOptions, base_gridOptions, forcedOptions, saveSizesDebounced]);
157
+
158
+ const dynamic_gridOptions = React.useMemo<AzGridOptions>(
159
+ () => {
160
+ const res = {};
161
+ dynamic_option_names.map((r) => {
162
+ res[r] = props[r];
163
+ });
164
+ return res;
165
+ },
166
+ dynamic_option_names.map((r) => props[r])
167
+ );
168
+
169
+ return (
170
+ <DataGridEventsWrapper
171
+ {...props}
172
+ gridRef={gridRef}
173
+ liveGridRef={liveGridRef}
174
+ static_gridOptions={static_gridOptions}
175
+ dynamic_gridOptions={dynamic_gridOptions}
176
+ columns={a11y_columns}
177
+ dataSource={dataSource}
178
+ highlightedRow={props.highlightedRow}
179
+ />
180
+ );
181
+ }
182
+
183
+ /* -------------------------------------------------------------------------- */
184
+ /**
185
+ * Wrapper for menu events
186
+ * @param props
187
+ * @returns
188
+ */
189
+ function DataGridEventsWrapper(props: DataGridWrapperProps) {
190
+ const themeClass = `azgrid-theme-${props.theme ?? (props.dark ? 'dark' : 'light')}`;
191
+ /* -------------------------------------------------------------------------- */
192
+ const {
193
+ onRowClick,
194
+ onRowContextMenu,
195
+ onRenderRow,
196
+ onRenderLoadMask,
197
+ update_menuRow,
198
+ menuAnchorEl,
199
+ menuRow,
200
+ } = useGridEvents(props.gridRef.current, props);
201
+ const menuRowId =
202
+ menuAnchorEl && !props.hideContextMenu && props.contextMenuItems
203
+ ? get_row_id(menuRow)
204
+ : undefined;
205
+ const consumerRowClassName = props.static_gridOptions?.rowClassName;
206
+ const rowClassName = React.useCallback(
207
+ (rowProps) => clsx(
208
+ typeof consumerRowClassName === 'function'
209
+ ? consumerRowClassName(rowProps)
210
+ : consumerRowClassName,
211
+ menuRowId != null && get_row_id(rowProps.data) === menuRowId && 'azgrid-row--menu-open'
212
+ ),
213
+ [consumerRowClassName, menuRowId]
214
+ );
215
+ /* -------------------------------------------------------------------------- */
216
+ /**
217
+ * Merge click events into grid options
218
+ */
219
+ const static_gridOptions = React.useMemo<AzGridOptions>(() => {
220
+ const opts: any = props.static_gridOptions || {};
221
+ const events: AzGridOptions = {
222
+ onRowClick: onRowClick,
223
+ onRowContextMenu: onRowContextMenu,
224
+ };
225
+
226
+ // internal row attributes first, consumer's onRenderRow last so it can override them
227
+ const consumerOnRenderRow = opts.onRenderRow;
228
+ const renderProps: any = {
229
+ rowClassName,
230
+ onRenderRow: consumerOnRenderRow
231
+ ? (rowProps) => {
232
+ onRenderRow(rowProps);
233
+ consumerOnRenderRow(rowProps);
234
+ }
235
+ : onRenderRow,
236
+ // track loading for aria-busy, the consumer's renderLoadMask (if any) still renders the mask
237
+ renderLoadMask: (maskProps) => {
238
+ onRenderLoadMask(maskProps);
239
+ return opts.renderLoadMask ? opts.renderLoadMask(maskProps) : undefined;
240
+ },
241
+ };
242
+
243
+ const gridEditable = !!props.editable;
244
+ const a11yProps: any = {
245
+ headerProps: { role: 'row', 'aria-rowindex': 1, ...opts.headerProps },
246
+ rowIndexColumn: apply_column_a11y(
247
+ typeof opts.rowIndexColumn === 'object' ? opts.rowIndexColumn : {},
248
+ { role: 'rowheader', gridEditable, id: rowIndexColumnId }
249
+ ),
250
+ };
251
+ if (opts.checkboxColumn)
252
+ a11yProps.checkboxColumn = apply_column_a11y(
253
+ typeof opts.checkboxColumn === 'object' ? opts.checkboxColumn : {},
254
+ { gridEditable, markReadonly: false, id: checkboxColumnId }
255
+ );
256
+
257
+ return {
258
+ ...opts,
259
+ ...events,
260
+ ...renderProps,
261
+ ...a11yProps,
262
+ };
263
+ }, [
264
+ props.static_gridOptions,
265
+ props.editable,
266
+ onRowClick,
267
+ onRowContextMenu,
268
+ onRenderRow,
269
+ onRenderLoadMask,
270
+ rowClassName,
271
+ ]);
272
+
273
+ /* -------------------------------------------------------------------------- */
274
+ // The menu is portaled to <body>, so it carries the theme class itself to get the theme tokens.
275
+ return (
276
+ <div className={clsx('azgrid-scope azgrid-flexed azgrid-flexlayout', themeClass)}>
277
+ {!props.hideContextMenu && props.contextMenuItems && (
278
+ <ContextMenu
279
+ classname={clsx('azgrid-context-menu', themeClass, props.contextMenuClassName)}
280
+ menuAnchorEl={menuAnchorEl}
281
+ menuRow={menuRow}
282
+ close={update_menuRow}
283
+ dontAutoClose={props.dontAutoCloseContextMenu ?? false}
284
+ escapeClosesContextMenu={props.escapeClosesContextMenu ?? false}
285
+ menu_items={props.contextMenuItems as any}
286
+ />
287
+ )}
288
+ {props.details_dataSource ? (
289
+ <DataGridDetailsWrapper {...props} static_gridOptions={static_gridOptions} />
290
+ ) : (
291
+ <DataGridSizeWrapper {...props} static_gridOptions={static_gridOptions} />
292
+ )}
293
+ </div>
294
+ );
295
+ }
296
+
297
+ function DataGridDetailsWrapper(props: DataGridWrapperProps) {
298
+ const cached_details_columns = useColumnData(props.details_columns);
299
+ const details_dataSource = useDataSource(props.details_dataSource, props);
300
+ const renderDetailsGrid = ({ data }) => {
301
+ return (
302
+ <ReactDataGrid
303
+ theme="default-light"
304
+ className={clsx('azgrid', `azgrid-theme-${props.theme ?? (props.dark ? 'dark' : 'light')}`)}
305
+ defaultFilterValue={props.details_filter}
306
+ dataSource={details_dataSource}
307
+ columns={cached_details_columns}
308
+ />
309
+ );
310
+ };
311
+
312
+ /**
313
+ * Merge details into grid
314
+ */
315
+ const static_gridOptions = React.useMemo<AzGridOptions>(() => {
316
+ const finalresult = props.static_gridOptions || {};
317
+ finalresult['renderDetailsGrid'] = renderDetailsGrid;
318
+ return finalresult;
319
+ }, [props.static_gridOptions, props.theme, props.dark]);
320
+
321
+ return <DataGridSizeWrapper {...props} static_gridOptions={static_gridOptions} />;
322
+ }
323
+
324
+ function DataGridSizeWrapper(props: DataGridWrapperProps) {
325
+ if (props.delayedSize) {
326
+ return <DataGridDelayedSizeWrapper {...props} />;
327
+ } else {
328
+ return <DataGridNormalSizeWrapper {...props} />;
329
+ }
330
+ }
331
+
332
+ /* -------------------------------------------------------------------------- */
333
+ function DataGridNormalSizeWrapper(props: DataGridWrapperProps) {
334
+ return props.advancedFilterFields ? (
335
+ <DataGridSearchWrapper {...props} />
336
+ ) : (
337
+ <DataGridCore {...props} />
338
+ );
339
+ }
340
+ function DataGridDelayedSizeWrapper(props: DataGridWrapperProps) {
341
+ const { ref, height, width } = useComponentSize();
342
+ return (
343
+ <div ref={ref} className={'azgrid-filler azgrid-nooverflow '}>
344
+ <div
345
+ className={'azgrid-delayedresize azgrid-flexlayout'}
346
+ style={{ height: height, width: width }}
347
+ >
348
+ {props.advancedFilterFields ? (
349
+ <DataGridSearchWrapper {...props} />
350
+ ) : (
351
+ <DataGridCore {...props} />
352
+ )}
353
+ </div>
354
+ </div>
355
+ );
356
+ }
357
+ function DataGridSearchWrapper(props: DataGridWrapperProps) {
358
+ const { element, filteredData } = useGridSearch(props);
359
+
360
+ return (
361
+ <div className={'azgrid-flexed azgrid-flexlayout azgrid-nooverflow'}>
362
+ {element}
363
+ <DataGridCore {...props} dataSource={filteredData} />
364
+ </div>
365
+ );
366
+ }
367
+ const DataGridCore = React.memo(DataGridCoreView, (prev, next) =>
368
+ core_prop_names.every((name) => prev[name] === next[name])
369
+ );
370
+ function DataGridCoreView(props: DataGridWrapperProps) {
371
+ const { gridRef, liveGridRef } = props;
372
+ const handle = React.useCallback(
373
+ (ref) => {
374
+ if (ref) gridRef.current = ref.current as any;
375
+ if (liveGridRef) liveGridRef.current = ref as any;
376
+ },
377
+ [gridRef, liveGridRef]
378
+ );
379
+ return (
380
+ <div className={clsx(props.className, 'azgrid-flexed', 'azgrid-flexlayout')}>
381
+ <ReactDataGrid
382
+ {...props.static_gridOptions}
383
+ {...props.dynamic_gridOptions}
384
+ rowIndexColumn={props.static_gridOptions.rowIndexColumn || true}
385
+ handle={handle}
386
+ theme="default-light"
387
+ className={clsx(
388
+ 'azgrid azgrid-flexed',
389
+ props.allowChildRows && 'azgrid-tree',
390
+ `azgrid-theme-${props.theme ?? (props.dark ? 'dark' : 'light')}`
391
+ )}
392
+ columns={props.columns}
393
+ dataSource={props.dataSource}
394
+ />
395
+ {props.children}
396
+ </div>
397
+ );
398
+ }
399
+ /* -------------------------------------------------------------------------- */
400
+ /* -------------------------------------------------------------------------- */
401
+ /* -------------------------------------------------------------------------- */
402
+ /* -------------------------------------------------------------------------- */
403
+
404
+ /* -------------------------------------------------------------------------- */
405
+ export default AzGrid;