@azrico/reactgrid 1.6.1 → 1.6.4

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.
@@ -7,6 +7,7 @@ import {
7
7
  apply_row_a11y,
8
8
  get_grid_root,
9
9
  get_root_a11y_key,
10
+ has_unsynced_header,
10
11
  is_grid_busy,
11
12
  } from '../func/func_a11y';
12
13
 
@@ -53,16 +54,17 @@ export function useGridEvents(grid: GridType, props: DataGridWrapperProps) {
53
54
  const onRowClick = React.useCallback((rowProps, event) => {
54
55
  const { onRowClick, onRowDoubleClick } = latestProps.current;
55
56
  const nowDate = Date.now();
56
- const lastclick: number = click_data.current[get_row_id(rowProps)];
57
+ const rowId = get_row_id(rowProps.data);
58
+ const lastclick: number = click_data.current[rowId];
57
59
  if (lastclick) {
58
60
  const diffTime = Math.abs(nowDate - lastclick);
59
61
  if (diffTime < 400) {
60
- click_data.current[get_row_id(rowProps)] = null;
62
+ click_data.current[rowId] = null;
61
63
  return onRowDoubleClick && onRowDoubleClick(rowProps.rowIndex, rowProps.data);
62
64
  }
63
65
  }
64
66
 
65
- click_data.current[get_row_id(rowProps)] = nowDate;
67
+ click_data.current[rowId] = nowDate;
66
68
  return onRowClick && onRowClick(rowProps.rowIndex, rowProps.data);
67
69
  }, []);
68
70
 
@@ -97,7 +99,7 @@ export function useGridEvents(grid: GridType, props: DataGridWrapperProps) {
97
99
  ariaLabel: latestProps.current.ariaLabel,
98
100
  editable: !!latestProps.current.editable,
99
101
  });
100
- // root attributes are set on the DOM node, batched to once per frame
102
+ // root and header cell attributes are set on the DOM nodes, batched to once per frame
101
103
  const scheduleRootSync = React.useCallback((force = false) => {
102
104
  if (rootSyncFrame.current || typeof requestAnimationFrame === 'undefined') return;
103
105
  const grid = latestProps.current.liveGridRef?.current?.current;
@@ -106,7 +108,8 @@ export function useGridEvents(grid: GridType, props: DataGridWrapperProps) {
106
108
  !force &&
107
109
  key &&
108
110
  key === lastRoot.current.key &&
109
- get_grid_root(grid) === lastRoot.current.el
111
+ get_grid_root(grid) === lastRoot.current.el &&
112
+ !has_unsynced_header(lastRoot.current.el)
110
113
  )
111
114
  return;
112
115
  rootSyncFrame.current = requestAnimationFrame(() => {
@@ -1,7 +1,7 @@
1
1
  /* Token overrides for Inovua 5.10.2. Generated by config/generate-theme.cjs.
2
2
  * index.css retains layout and icons. Public tokens are inherited; preset tokens
3
3
  * are fallback implementation details. Do not set public defaults on the root. */
4
- .azgrid-scope, .azgrid, .azgrid-theme-light {
4
+ .azgrid-scope, .azgrid, .azgrid-theme-light, .azgrid-context-menu {
5
5
  --azgrid-preset-bg: #fff;
6
6
  --azgrid-preset-fg: #555e68;
7
7
  --azgrid-preset-border: #e4e3e2;
@@ -2010,23 +2010,18 @@
2010
2010
  .azgrid-scope .inovua-react-toolkit-menu {
2011
2011
  border-radius: var(--azgrid-radius, var(--azgrid-preset-radius));
2012
2012
  }
2013
- /* Three classes exceed MUI's generated Paper/MenuItem selector specificity. */
2014
- .azgrid-scope .azgrid-context-menu.MuiPaper-root {
2015
- background: var(--azgrid-menu-bg, var(--azgrid-preset-menu-bg));
2016
- color: var(--azgrid-menu-fg, var(--azgrid-preset-menu-fg));
2013
+ /* The row context menu is portaled to <body>, outside .azgrid-scope: these rules stay
2014
+ * unscoped and read the tokens from the theme class DataGrid puts on the menu.
2015
+ * Two classes exceed @azrico/controls' single-class menu rules. */
2016
+ .azgrid-context-menu.azrico-controls-contextmenu {
2017
+ --azrico-contextmenu-color: var(--azgrid-menu-fg, var(--azgrid-preset-menu-fg));
2018
+ --azrico-contextmenu-background: var(--azgrid-menu-bg, var(--azgrid-preset-menu-bg));
2019
+ --azrico-contextmenu-hover: var(--azgrid-menu-bg-hover, var(--azgrid-preset-menu-bg-hover));
2020
+ --azrico-contextmenu-focus: var(--azgrid-accent, var(--azgrid-preset-accent));
2021
+ --azrico-contextmenu-radius: var(--azgrid-radius, var(--azgrid-preset-radius));
2022
+ --azrico-contextmenu-shadow: 0 3px 8px var(--azgrid-shadow-color, var(--azgrid-preset-shadow-color));
2023
+ --azrico-contextmenu-font: var(--azgrid-font-family, var(--azgrid-preset-font-family));
2017
2024
  border: 1px solid var(--azgrid-menu-border, var(--azgrid-preset-menu-border));
2018
- border-radius: var(--azgrid-radius, var(--azgrid-preset-radius));
2019
- box-shadow: 0 3px 8px var(--azgrid-shadow-color, var(--azgrid-preset-shadow-color));
2020
- font-family: var(--azgrid-font-family, var(--azgrid-preset-font-family));
2021
- }
2022
- .azgrid-scope .azgrid-context-menu .MuiTypography-root,
2023
- .azgrid-scope .azgrid-context-menu .MuiMenuItem-root {
2024
- color: inherit;
2025
- font-family: inherit;
2026
- }
2027
- .azgrid-scope .azgrid-context-menu .MuiMenuItem-root:hover,
2028
- .azgrid-scope .azgrid-context-menu .MuiMenuItem-root.Mui-focusVisible {
2029
- background: var(--azgrid-menu-bg-hover, var(--azgrid-preset-menu-bg-hover));
2030
2025
  }
2031
2026
  .azgrid-scope, .azgrid-scope * {
2032
2027
  accent-color: var(--azgrid-accent, var(--azgrid-preset-accent));
@@ -1,153 +1,157 @@
1
- import { ModifyFields } from '../func/func_grid';
2
- import { ConvertableToMenuItem } from '@azrico/controls/context-menu';
3
- import React from 'react';
4
- import {
5
- TypeCellSelection,
6
- TypeColumn,
7
- TypeDataGridProps,
8
- TypeDataSource,
9
- TypeEditInfo,
10
- TypeFilterTypes,
11
- TypeFilterValue,
12
- TypeRowDetailsInfo,
13
- TypeRowProps,
14
- TypeRowSelection,
15
- TypeComputedProps,
16
- TypeSortInfo,
17
- TypeGroupBy,
18
- } from '@inovua/reactdatagrid-community/types';
19
-
20
- import { TypeOnSelectionChangeArg } from '@inovua/reactdatagrid-community/types/TypeDataGridProps';
21
-
22
- /* -------------------------------------------------------------------------- */
23
- export type ColumnDefinition = TypeColumn;
24
- export type CellDefinition = any;
25
- export type RowDefinition = any;
26
- export type RowProps = TypeRowProps;
27
- export type RowSelectionValue = TypeRowSelection;
28
- export type CellSelectionValue = TypeCellSelection;
29
- export type DataRowDefinition = any;
30
- export type FilterTypes = TypeFilterTypes;
31
- export type FilterValues = TypeFilterValue;
32
- export type DataSourceDefinition = TypeDataSource;
33
- export type OnSelectionChangeFunc = (config: TypeOnSelectionChangeArg) => void;
34
- export type OnCellSelectionChangeFunc = (s: { [key: string]: boolean }) => void;
35
- export type RowDetailsFunc = (rowDetailsInfo: TypeRowDetailsInfo) => React.ReactNode;
36
-
37
- export type loose_column_names = {
38
- key: string;
39
- field: string;
40
- columnName: string;
41
- name: string;
42
- };
43
- export type loose_column_fields = loose_column_names & {
44
- title: string;
45
- type: string;
46
- items: any[];
47
- /** accessible name for cells whose visible text isn't descriptive (icons, badges, ...), set as aria-label */
48
- ariaLabel: (value: any, data: any) => string;
49
- };
50
- export type LooseColumnDefinition = Partial<loose_column_fields & ColumnDefinition>;
51
- //
52
-
53
- export type CustomColumnDefinition = {
54
- name: string;
55
- render: (cell: any, formatterParams, onRendered) => React.ReactNode | undefined | null;
56
- };
57
- export type AzGridOptions = Partial<TypeDataGridProps> & {
58
- /** called for every rendered row, after the grid's own row attributes are set */
59
- onRenderRow?: (rowProps: any) => void;
60
- /** extra DOM props for the header row */
61
- headerProps?: { [key: string]: any };
62
- };
63
- /** arguments passed to a dataSource function */
64
- export type AzDataSourceParams = {
65
- skip?: number;
66
- limit?: number;
67
- /** current header filters, filter.value is an array of selected ids for a multi-select SelectFilter */
68
- filterValue?: TypeFilterValue;
69
- sortInfo?: TypeSortInfo;
70
- groupBy?: TypeGroupBy;
71
- cached_data: React.MutableRefObject<any>;
72
- last_cache_info: React.MutableRefObject<any>;
73
- };
74
- export type AzDataSourceFunc = (args: AzDataSourceParams) => any[] | Promise<any[] | any>;
75
- /* -------------------------------------------------------------------------- */
76
- export type AzGridProps = {
77
- dataSource?: any[] | AzDataSourceFunc;
78
- details_dataSource?: any[] | AzDataSourceFunc; //details is rendered under each row
79
- details_columns?: LooseColumnDefinition[];
80
- details_filter?: FilterValues;
81
-
82
- licenseKey?: string;
83
- /** accessible name of the grid, set as aria-label on the grid root */
84
- ariaLabel?: string;
85
-
86
- gridRef?: React.MutableRefObject<TypeComputedProps>;
87
- gridOptions?: AzGridOptions;
88
-
89
- columns?: LooseColumnDefinition[];
90
- columnExtensions?: Partial<LooseColumnDefinition>;
91
-
92
- editableColumns?: string[];
93
- leftColumns?: string[];
94
- rightColumns?: string[];
95
- customColumns?: CustomColumnDefinition[];
96
-
97
- contextMenuItems?: ConvertableToMenuItem;
98
-
99
- highlightedRow?: any;
100
- RowDetail?: RowDetailsFunc;
101
-
102
- selected?: RowSelectionValue;
103
- cellSelection?: CellSelectionValue;
104
- /* -------------------------------------------------------------------------- */
105
- onEditComplete?: (editInfo: TypeEditInfo) => void;
106
- onSelectionChange?: OnSelectionChangeFunc;
107
- onCellSelectionChange?: OnCellSelectionChangeFunc;
108
-
109
- onRowClick?: (rowIndex: number, row: any) => void;
110
- onRowDoubleClick?: (rowIndex: number, row: any) => void;
111
- onLimitChange?: (v: number) => void;
112
- onSkipChange?: (v: number) => void;
113
- /* -------------------------------------------------------------------------- */
114
- skip?: number;
115
- limit?: number;
116
- //
117
- editable?: boolean | ((editValue: any, cellProps: any) => boolean);
118
- advancedFilterFields?: string[];
119
- /** Label of the quick-search box shown with `advancedFilterFields`. Default "Search". */
120
- advancedFilterLabel?: React.ReactNode;
121
- /** Placeholder of the quick-search input. A string is used as the native placeholder, any other node (custom HTML) is shown over the empty input. */
122
- advancedFilterPlaceholder?: React.ReactNode;
123
- //
124
-
125
- loading?: boolean;
126
- theme?: 'light' | 'dark' | (string & {});
127
- /** @deprecated Use theme="dark" or theme="light" instead. */
128
- dark?: boolean;
129
- delayedSize?: boolean;
130
- allowChildRows?: boolean;
131
- looseCacheCheck?: boolean;
132
- className?: string;
133
- };
134
-
135
- export type DataGridProps = ModifyFields<
136
- AzGridProps,
137
- {
138
- columns: ColumnDefinition[];
139
- dataSource: any;
140
- }
141
- >;
142
- export type GridType = TypeComputedProps;
143
- export type DataGridWrapperProps = ModifyFields<
144
- DataGridProps,
145
- {
146
- gridRef: React.MutableRefObject<TypeComputedProps>;
147
- /** internal: inovua's live computed props ref (gridRef holds a snapshot) */
148
- liveGridRef: React.MutableRefObject<React.MutableRefObject<TypeComputedProps> | null>;
149
- static_gridOptions: AzGridOptions;
150
- dynamic_gridOptions: AzGridOptions;
151
- children?: React.ReactNode;
152
- }
153
- >;
1
+ import { ModifyFields } from '../func/func_grid';
2
+ import { ConvertableToMenuItem } from '@azrico/controls/context-menu';
3
+ import React from 'react';
4
+ import {
5
+ TypeCellSelection,
6
+ TypeColumn,
7
+ TypeDataGridProps,
8
+ TypeDataSource,
9
+ TypeEditInfo,
10
+ TypeFilterTypes,
11
+ TypeFilterValue,
12
+ TypeRowDetailsInfo,
13
+ TypeRowProps,
14
+ TypeRowSelection,
15
+ TypeComputedProps,
16
+ TypeSortInfo,
17
+ TypeGroupBy,
18
+ } from '@inovua/reactdatagrid-community/types';
19
+
20
+ import { TypeOnSelectionChangeArg } from '@inovua/reactdatagrid-community/types/TypeDataGridProps';
21
+
22
+ /* -------------------------------------------------------------------------- */
23
+ export type ColumnDefinition = TypeColumn;
24
+ export type CellDefinition = any;
25
+ export type RowDefinition = any;
26
+ export type RowProps = TypeRowProps;
27
+ export type RowSelectionValue = TypeRowSelection;
28
+ export type CellSelectionValue = TypeCellSelection;
29
+ export type DataRowDefinition = any;
30
+ export type FilterTypes = TypeFilterTypes;
31
+ export type FilterValues = TypeFilterValue;
32
+ export type DataSourceDefinition = TypeDataSource;
33
+ export type OnSelectionChangeFunc = (config: TypeOnSelectionChangeArg) => void;
34
+ export type OnCellSelectionChangeFunc = (s: { [key: string]: boolean }) => void;
35
+ export type RowDetailsFunc = (rowDetailsInfo: TypeRowDetailsInfo) => React.ReactNode;
36
+
37
+ export type loose_column_names = {
38
+ key: string;
39
+ field: string;
40
+ columnName: string;
41
+ name: string;
42
+ };
43
+ export type loose_column_fields = loose_column_names & {
44
+ title: string;
45
+ type: string;
46
+ items: any[];
47
+ /** accessible name for cells whose visible text isn't descriptive (icons, badges, ...), set as aria-label */
48
+ ariaLabel: (value: any, data: any) => string;
49
+ };
50
+ export type LooseColumnDefinition = Partial<loose_column_fields & ColumnDefinition>;
51
+ //
52
+
53
+ export type CustomColumnDefinition = {
54
+ name: string;
55
+ render: (cell: any, formatterParams, onRendered) => React.ReactNode | undefined | null;
56
+ };
57
+ export type AzGridOptions = Partial<TypeDataGridProps> & {
58
+ /** called for every rendered row, after the grid's own row attributes are set */
59
+ onRenderRow?: (rowProps: any) => void;
60
+ /** extra DOM props for the header row */
61
+ headerProps?: { [key: string]: any };
62
+ };
63
+ /** arguments passed to a dataSource function */
64
+ export type AzDataSourceParams = {
65
+ skip?: number;
66
+ limit?: number;
67
+ /** current header filters, filter.value is an array of selected ids for a multi-select SelectFilter */
68
+ filterValue?: TypeFilterValue;
69
+ sortInfo?: TypeSortInfo;
70
+ groupBy?: TypeGroupBy;
71
+ cached_data: React.MutableRefObject<any>;
72
+ last_cache_info: React.MutableRefObject<any>;
73
+ };
74
+ export type AzDataSourceFunc = (args: AzDataSourceParams) => any[] | Promise<any[] | any>;
75
+ /* -------------------------------------------------------------------------- */
76
+ export type AzGridProps = {
77
+ dataSource?: any[] | AzDataSourceFunc;
78
+ details_dataSource?: any[] | AzDataSourceFunc; //details is rendered under each row
79
+ details_columns?: LooseColumnDefinition[];
80
+ details_filter?: FilterValues;
81
+
82
+ licenseKey?: string;
83
+ /** accessible name of the grid, set as aria-label on the grid root */
84
+ ariaLabel?: string;
85
+
86
+ gridRef?: React.MutableRefObject<TypeComputedProps>;
87
+ gridOptions?: AzGridOptions;
88
+
89
+ columns?: LooseColumnDefinition[];
90
+ columnExtensions?: Partial<LooseColumnDefinition>;
91
+
92
+ editableColumns?: string[];
93
+ leftColumns?: string[];
94
+ rightColumns?: string[];
95
+ customColumns?: CustomColumnDefinition[];
96
+
97
+ contextMenuItems?: ConvertableToMenuItem;
98
+ /** Extra classes on the row context menu, which is portaled to <body> */
99
+ contextMenuClassName?: string;
100
+
101
+ highlightedRow?: any;
102
+ RowDetail?: RowDetailsFunc;
103
+
104
+ selected?: RowSelectionValue;
105
+ cellSelection?: CellSelectionValue;
106
+ /* -------------------------------------------------------------------------- */
107
+ onEditComplete?: (editInfo: TypeEditInfo) => void;
108
+ onSelectionChange?: OnSelectionChangeFunc;
109
+ onCellSelectionChange?: OnCellSelectionChangeFunc;
110
+
111
+ onRowClick?: (rowIndex: number, row: any) => void;
112
+ onRowDoubleClick?: (rowIndex: number, row: any) => void;
113
+ onLimitChange?: (v: number) => void;
114
+ onSkipChange?: (v: number) => void;
115
+ /* -------------------------------------------------------------------------- */
116
+ skip?: number;
117
+ limit?: number;
118
+ //
119
+ editable?: boolean | ((editValue: any, cellProps: any) => boolean);
120
+ advancedFilterFields?: string[];
121
+ /** Label of the quick-search box shown with `advancedFilterFields`. Default "Search". */
122
+ advancedFilterLabel?: React.ReactNode;
123
+ /** Placeholder of the quick-search input. A string is used as the native placeholder, any other node (custom HTML) is shown over the empty input. */
124
+ advancedFilterPlaceholder?: React.ReactNode;
125
+ //
126
+
127
+ loading?: boolean;
128
+ theme?: 'light' | 'dark' | (string & {});
129
+ /** @deprecated Use theme="dark" or theme="light" instead. */
130
+ dark?: boolean;
131
+ delayedSize?: boolean;
132
+ allowChildRows?: boolean;
133
+ looseCacheCheck?: boolean;
134
+ className?: string;
135
+ /** rendered after the grid, inside its container */
136
+ children?: React.ReactNode;
137
+ };
138
+
139
+ export type DataGridProps = ModifyFields<
140
+ AzGridProps,
141
+ {
142
+ columns: ColumnDefinition[];
143
+ dataSource: any;
144
+ }
145
+ >;
146
+ export type GridType = TypeComputedProps;
147
+ export type DataGridWrapperProps = ModifyFields<
148
+ DataGridProps,
149
+ {
150
+ gridRef: React.MutableRefObject<TypeComputedProps>;
151
+ /** internal: inovua's live computed props ref (gridRef holds a snapshot) */
152
+ liveGridRef: React.MutableRefObject<React.MutableRefObject<TypeComputedProps> | null>;
153
+ static_gridOptions: AzGridOptions;
154
+ dynamic_gridOptions: AzGridOptions;
155
+ children?: React.ReactNode;
156
+ }
157
+ >;
@@ -4,7 +4,6 @@ import '../themes/grid.css';
4
4
  import { get_default_key } from '../func/func_grid';
5
5
  import { ContextMenu } from '@azrico/controls/context-menu';
6
6
  import React from 'react';
7
- import { createTheme, ThemeProvider, useTheme } from '@mui/material/styles';
8
7
 
9
8
  import ReactDataGrid from '@inovua/reactdatagrid-enterprise';
10
9
  import clsx from 'clsx';
@@ -16,6 +15,8 @@ import { useColumnData } from '../hooks/useColumnData';
16
15
  import { useDataSource } from '../hooks/useDatasource';
17
16
  import { useGridSearch } from '../hooks/useGridSearch';
18
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';
19
20
  /* -------------------------------------------------------------------------- */
20
21
 
21
22
  /* -------------------------------------------------------------------------- */
@@ -152,15 +153,6 @@ export function AzGrid(props: AzGridProps) {
152
153
  * @returns
153
154
  */
154
155
  function DataGridEventsWrapper(props: DataGridWrapperProps) {
155
- const scopeRef = React.useRef<HTMLDivElement>(null);
156
- const hostTheme = useTheme();
157
- // Keep the existing context menu and its portal in this grid's CSS scope.
158
- const menuTheme = React.useMemo(
159
- () => createTheme(hostTheme, {
160
- components: { MuiPopper: { defaultProps: { container: () => scopeRef.current } } },
161
- }),
162
- [hostTheme]
163
- );
164
156
  const themeClass = `azgrid-theme-${props.theme ?? (props.dark ? 'dark' : 'light')}`;
165
157
  /* -------------------------------------------------------------------------- */
166
158
  const {
@@ -204,13 +196,13 @@ function DataGridEventsWrapper(props: DataGridWrapperProps) {
204
196
  headerProps: { role: 'row', 'aria-rowindex': 1, ...opts.headerProps },
205
197
  rowIndexColumn: apply_column_a11y(
206
198
  typeof opts.rowIndexColumn === 'object' ? opts.rowIndexColumn : {},
207
- { role: 'rowheader', gridEditable }
199
+ { role: 'rowheader', gridEditable, id: rowIndexColumnId }
208
200
  ),
209
201
  };
210
202
  if (opts.checkboxColumn)
211
203
  a11yProps.checkboxColumn = apply_column_a11y(
212
204
  typeof opts.checkboxColumn === 'object' ? opts.checkboxColumn : {},
213
- { gridEditable, markReadonly: false }
205
+ { gridEditable, markReadonly: false, id: checkboxColumnId }
214
206
  );
215
207
 
216
208
  return {
@@ -229,19 +221,17 @@ function DataGridEventsWrapper(props: DataGridWrapperProps) {
229
221
  ]);
230
222
 
231
223
  /* -------------------------------------------------------------------------- */
232
- //TODO ContextMenu not from mui...
224
+ // The menu is portaled to <body>, so it carries the theme class itself to get the theme tokens.
233
225
  return (
234
- <div ref={scopeRef} className={clsx('azgrid-scope azgrid-flexed azgrid-flexlayout', themeClass)}>
235
- <ThemeProvider theme={menuTheme}>
236
- <ContextMenu
237
- classname="azgrid-context-menu"
238
- menuAnchorEl={menuAnchorEl}
239
- menuRow={menuRow}
240
- close={update_menuRow}
241
- dontAutoClose={false}
242
- menu_items={props.contextMenuItems as any}
243
- />
244
- </ThemeProvider>
226
+ <div className={clsx('azgrid-scope azgrid-flexed azgrid-flexlayout', themeClass)}>
227
+ <ContextMenu
228
+ classname={clsx('azgrid-context-menu', themeClass, props.contextMenuClassName)}
229
+ menuAnchorEl={menuAnchorEl}
230
+ menuRow={menuRow}
231
+ close={update_menuRow}
232
+ dontAutoClose={false}
233
+ menu_items={props.contextMenuItems as any}
234
+ />
245
235
  {props.details_dataSource ? (
246
236
  <DataGridDetailsWrapper {...props} static_gridOptions={static_gridOptions} />
247
237
  ) : (