@azrico/reactgrid 1.6.5 → 1.6.6
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 +1 -0
- package/__tests__/context-menu.test.js +40 -2
- package/dist/src/hooks/useGridEvents.js +4 -1
- package/dist/src/types/types.d.ts +4 -0
- package/dist/src/views/DataGrid.js +3 -3
- package/package.json +1 -1
- package/src/hooks/useGridEvents.ts +11 -1
- package/src/types/types.ts +4 -0
- package/src/views/DataGrid.tsx +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file. See [standa
|
|
|
4
4
|
|
|
5
5
|
### Unreleased
|
|
6
6
|
|
|
7
|
+
* Add `dontAutoCloseContextMenu` to keep the row context menu open on outside clicks, and `hideContextMenu` to hide it while leaving the browser's context menu available.
|
|
7
8
|
* Fix columns with a `type` (`number`, `select`, `bool`, ...) staying read-only unless they were listed in `editableColumns`. A typed column is editable unless you set `editable: false`.
|
|
8
9
|
* Fix a typed column's `editable` function being replaced by `true`. Functions and booleans are kept, so per-cell editability works again.
|
|
9
10
|
* Fix select `items` given as plain strings storing a lowercased value (`"Shelf A"` was saved as `"shelf a"`). The item id is now the original string.
|
|
@@ -41,9 +41,9 @@ afterEach(() => {
|
|
|
41
41
|
jest.restoreAllMocks();
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
function render(contextMenuItems) {
|
|
44
|
+
function render(contextMenuItems, props = {}) {
|
|
45
45
|
act(() => root.render(React.createElement(AzGrid, {
|
|
46
|
-
columns: [], dataSource: [row], contextMenuItems,
|
|
46
|
+
columns: [], dataSource: [row], contextMenuItems, ...props,
|
|
47
47
|
})));
|
|
48
48
|
}
|
|
49
49
|
function rightClick(data = rowProps, alreadyHandled = false) {
|
|
@@ -131,6 +131,44 @@ test('clicking outside closes the menu', async () => {
|
|
|
131
131
|
expect(popup()).toBeNull();
|
|
132
132
|
});
|
|
133
133
|
|
|
134
|
+
test('dontAutoCloseContextMenu keeps the menu open on outside clicks and can be updated', async () => {
|
|
135
|
+
const items = ['Open'];
|
|
136
|
+
render(items, { dontAutoCloseContextMenu: true });
|
|
137
|
+
rightClick();
|
|
138
|
+
await act(() => new Promise((resolve) => setTimeout(resolve, 0)));
|
|
139
|
+
act(() => document.body.click());
|
|
140
|
+
expect(popup()).not.toBeNull();
|
|
141
|
+
render(items, { dontAutoCloseContextMenu: false });
|
|
142
|
+
await act(() => new Promise((resolve) => setTimeout(resolve, 0)));
|
|
143
|
+
act(() => document.body.click());
|
|
144
|
+
expect(popup()).toBeNull();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test('hideContextMenu omits the menu without evaluating items or suppressing the native menu', () => {
|
|
148
|
+
const items = jest.fn(() => ['Open']);
|
|
149
|
+
render(items, { hideContextMenu: true });
|
|
150
|
+
expect(rightClick().defaultPrevented).toBe(false);
|
|
151
|
+
expect(items).not.toHaveBeenCalled();
|
|
152
|
+
expect(ContextMenu).not.toHaveBeenCalled();
|
|
153
|
+
expect(popup()).toBeNull();
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test('hiding an open menu closes it and showing it again waits for a fresh right-click', () => {
|
|
157
|
+
const items = ['Open'];
|
|
158
|
+
render(items);
|
|
159
|
+
const handler = mockGridProps.onRowContextMenu;
|
|
160
|
+
rightClick();
|
|
161
|
+
expect(popup()).not.toBeNull();
|
|
162
|
+
render(items, { hideContextMenu: true });
|
|
163
|
+
expect(popup()).toBeNull();
|
|
164
|
+
expect(mockGridProps.onRowContextMenu).toBe(handler);
|
|
165
|
+
expect(rightClick().defaultPrevented).toBe(false);
|
|
166
|
+
render(items, { hideContextMenu: false });
|
|
167
|
+
expect(popup()).toBeNull();
|
|
168
|
+
expect(rightClick().defaultPrevented).toBe(true);
|
|
169
|
+
expect(popup()).not.toBeNull();
|
|
170
|
+
});
|
|
171
|
+
|
|
134
172
|
test('does not open or evaluate grid items for a right-click already handled by row details', () => {
|
|
135
173
|
const items = jest.fn(() => ['Open']);
|
|
136
174
|
render(items);
|
|
@@ -77,8 +77,11 @@ function useGridEvents(grid, props) {
|
|
|
77
77
|
click_data.current = {};
|
|
78
78
|
}, [props.dataSource]);
|
|
79
79
|
/* ------------------------------- ContextMenu ------------------------------ */
|
|
80
|
+
_react.default.useEffect(() => {
|
|
81
|
+
if (props.hideContextMenu) update_menuRow(null, null);
|
|
82
|
+
}, [props.hideContextMenu, update_menuRow]);
|
|
80
83
|
const onRowContextMenu = _react.default.useCallback((rowProps, event) => {
|
|
81
|
-
if (event.defaultPrevented || !rowProps || !rowProps.data || _func_child.func_selection.has_selection()) {
|
|
84
|
+
if (latestProps.current.hideContextMenu || event.defaultPrevented || !rowProps || !rowProps.data || _func_child.func_selection.has_selection()) {
|
|
82
85
|
update_menuRow(null, null);
|
|
83
86
|
return true;
|
|
84
87
|
}
|
|
@@ -73,6 +73,10 @@ export type AzGridProps = {
|
|
|
73
73
|
rightColumns?: string[];
|
|
74
74
|
customColumns?: CustomColumnDefinition[];
|
|
75
75
|
contextMenuItems?: ConvertableToMenuItem;
|
|
76
|
+
/** Keep the context menu open when clicking outside (default false). */
|
|
77
|
+
dontAutoCloseContextMenu?: boolean;
|
|
78
|
+
/** Hide the grid context menu and leave the browser's context menu available. */
|
|
79
|
+
hideContextMenu?: boolean;
|
|
76
80
|
/** Extra classes on the row context menu, which is portaled to <body> */
|
|
77
81
|
contextMenuClassName?: string;
|
|
78
82
|
highlightedRow?: any;
|
|
@@ -121,7 +121,7 @@ function AzGrid(props) {
|
|
|
121
121
|
* @returns
|
|
122
122
|
*/
|
|
123
123
|
function DataGridEventsWrapper(props) {
|
|
124
|
-
var _props$theme;
|
|
124
|
+
var _props$theme, _props$dontAutoCloseC;
|
|
125
125
|
const themeClass = `azgrid-theme-${(_props$theme = props.theme) !== null && _props$theme !== void 0 ? _props$theme : props.dark ? 'dark' : 'light'}`;
|
|
126
126
|
/* -------------------------------------------------------------------------- */
|
|
127
127
|
const {
|
|
@@ -185,12 +185,12 @@ function DataGridEventsWrapper(props) {
|
|
|
185
185
|
// The menu is portaled to <body>, so it carries the theme class itself to get the theme tokens.
|
|
186
186
|
return _react.default.createElement("div", {
|
|
187
187
|
className: (0, _clsx.default)('azgrid-scope azgrid-flexed azgrid-flexlayout', themeClass)
|
|
188
|
-
}, props.contextMenuItems && _react.default.createElement(_contextMenu.ContextMenu, {
|
|
188
|
+
}, !props.hideContextMenu && props.contextMenuItems && _react.default.createElement(_contextMenu.ContextMenu, {
|
|
189
189
|
classname: (0, _clsx.default)('azgrid-context-menu', themeClass, props.contextMenuClassName),
|
|
190
190
|
menuAnchorEl: menuAnchorEl,
|
|
191
191
|
menuRow: menuRow,
|
|
192
192
|
close: update_menuRow,
|
|
193
|
-
dontAutoClose: false,
|
|
193
|
+
dontAutoClose: (_props$dontAutoCloseC = props.dontAutoCloseContextMenu) !== null && _props$dontAutoCloseC !== void 0 ? _props$dontAutoCloseC : false,
|
|
194
194
|
menu_items: props.contextMenuItems
|
|
195
195
|
}), props.details_dataSource ? _react.default.createElement(DataGridDetailsWrapper, {
|
|
196
196
|
...props,
|
package/package.json
CHANGED
|
@@ -74,8 +74,18 @@ export function useGridEvents(grid: GridType, props: DataGridWrapperProps) {
|
|
|
74
74
|
}, [props.dataSource]);
|
|
75
75
|
|
|
76
76
|
/* ------------------------------- ContextMenu ------------------------------ */
|
|
77
|
+
React.useEffect(() => {
|
|
78
|
+
if (props.hideContextMenu) update_menuRow(null, null);
|
|
79
|
+
}, [props.hideContextMenu, update_menuRow]);
|
|
80
|
+
|
|
77
81
|
const onRowContextMenu = React.useCallback((rowProps, event) => {
|
|
78
|
-
if (
|
|
82
|
+
if (
|
|
83
|
+
latestProps.current.hideContextMenu ||
|
|
84
|
+
event.defaultPrevented ||
|
|
85
|
+
!rowProps ||
|
|
86
|
+
!rowProps.data ||
|
|
87
|
+
func_selection.has_selection()
|
|
88
|
+
) {
|
|
79
89
|
update_menuRow(null, null);
|
|
80
90
|
return true;
|
|
81
91
|
}
|
package/src/types/types.ts
CHANGED
|
@@ -95,6 +95,10 @@ export type AzGridProps = {
|
|
|
95
95
|
customColumns?: CustomColumnDefinition[];
|
|
96
96
|
|
|
97
97
|
contextMenuItems?: ConvertableToMenuItem;
|
|
98
|
+
/** Keep the context menu open when clicking outside (default false). */
|
|
99
|
+
dontAutoCloseContextMenu?: boolean;
|
|
100
|
+
/** Hide the grid context menu and leave the browser's context menu available. */
|
|
101
|
+
hideContextMenu?: boolean;
|
|
98
102
|
/** Extra classes on the row context menu, which is portaled to <body> */
|
|
99
103
|
contextMenuClassName?: string;
|
|
100
104
|
|
package/src/views/DataGrid.tsx
CHANGED
|
@@ -224,13 +224,13 @@ function DataGridEventsWrapper(props: DataGridWrapperProps) {
|
|
|
224
224
|
// The menu is portaled to <body>, so it carries the theme class itself to get the theme tokens.
|
|
225
225
|
return (
|
|
226
226
|
<div className={clsx('azgrid-scope azgrid-flexed azgrid-flexlayout', themeClass)}>
|
|
227
|
-
{props.contextMenuItems && (
|
|
227
|
+
{!props.hideContextMenu && props.contextMenuItems && (
|
|
228
228
|
<ContextMenu
|
|
229
229
|
classname={clsx('azgrid-context-menu', themeClass, props.contextMenuClassName)}
|
|
230
230
|
menuAnchorEl={menuAnchorEl}
|
|
231
231
|
menuRow={menuRow}
|
|
232
232
|
close={update_menuRow}
|
|
233
|
-
dontAutoClose={false}
|
|
233
|
+
dontAutoClose={props.dontAutoCloseContextMenu ?? false}
|
|
234
234
|
menu_items={props.contextMenuItems as any}
|
|
235
235
|
/>
|
|
236
236
|
)}
|