@xh/hoist 77.0.0-SNAPSHOT.1761690719868 → 77.0.0-SNAPSHOT.1761769225395
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 +5 -3
- package/build/types/cmp/grid/impl/MenuSupport.d.ts +2 -2
- package/build/types/data/RecordAction.d.ts +9 -19
- package/build/types/kit/ag-grid/index.d.ts +2 -2
- package/cmp/ag-grid/AgGridModel.ts +16 -19
- package/cmp/grid/impl/MenuSupport.ts +68 -25
- package/data/RecordAction.ts +16 -10
- package/kit/ag-grid/index.ts +2 -2
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 76.2.1 - 2025-10-29
|
|
4
4
|
|
|
5
5
|
### 🐞 Bug Fixes
|
|
6
6
|
* Fixes regressions in grid context menu for filtering and copy/paste introduced by agGrid v34.
|
|
7
|
+
* Fixes `getExpandState` in `AgGridModel`
|
|
7
8
|
|
|
8
|
-
* Note: AgGrid no longer supports html markup in context menus. Applications setting
|
|
9
|
-
|
|
9
|
+
* Note: As of v34, AgGrid no longer supports html markup in context menus. Applications setting
|
|
10
|
+
the `text` or `secondaryText` properties of `RecordGridAction` to markup should be sure to use
|
|
11
|
+
react nodes for formatting instead.
|
|
10
12
|
|
|
11
13
|
### 💥 Breaking Changes
|
|
12
14
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { GridModel } from '@xh/hoist/cmp/grid';
|
|
2
|
-
import {
|
|
3
|
-
import type {
|
|
2
|
+
import { type GetContextMenuItemsParams, type MenuItemDef } from '@xh/hoist/kit/ag-grid';
|
|
3
|
+
import type { GridContextMenuSpec } from '../GridContextMenu';
|
|
4
4
|
/**
|
|
5
5
|
* @internal
|
|
6
6
|
*/
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { ReactElement } from 'react';
|
|
2
|
-
import { Intent,
|
|
1
|
+
import { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import { Intent, TestSupportProps } from '../core';
|
|
3
3
|
import { StoreRecord } from './StoreRecord';
|
|
4
4
|
import { Column, GridModel } from '../cmp/grid';
|
|
5
5
|
export interface RecordActionSpec extends TestSupportProps {
|
|
6
6
|
/** Label to be displayed. */
|
|
7
|
-
text?:
|
|
7
|
+
text?: ReactNode;
|
|
8
8
|
/** Additional label to be displayed, usually in a minimal fashion.*/
|
|
9
|
-
secondaryText?:
|
|
9
|
+
secondaryText?: ReactNode;
|
|
10
10
|
/** Icon to be displayed.*/
|
|
11
11
|
icon?: ReactElement;
|
|
12
12
|
/** Intent to be used for rendering the action.*/
|
|
@@ -72,15 +72,15 @@ export interface ActionFnData {
|
|
|
72
72
|
* @see GridContextMenuSpec
|
|
73
73
|
*/
|
|
74
74
|
export declare class RecordAction {
|
|
75
|
-
text:
|
|
76
|
-
secondaryText:
|
|
75
|
+
text: ReactNode;
|
|
76
|
+
secondaryText: ReactNode;
|
|
77
77
|
icon: ReactElement;
|
|
78
78
|
intent: Intent;
|
|
79
79
|
className: string;
|
|
80
80
|
tooltip: string;
|
|
81
81
|
actionFn: (data: ActionFnData) => void;
|
|
82
|
-
displayFn: (data: ActionFnData) =>
|
|
83
|
-
items:
|
|
82
|
+
displayFn: (data: ActionFnData) => RecordActionSpec;
|
|
83
|
+
items: RecordActionLike[];
|
|
84
84
|
disabled: boolean;
|
|
85
85
|
hidden: boolean;
|
|
86
86
|
recordsRequired: boolean | number;
|
|
@@ -90,17 +90,7 @@ export declare class RecordAction {
|
|
|
90
90
|
* Called by UI elements to get the display configuration for rendering the action.
|
|
91
91
|
* @internal
|
|
92
92
|
*/
|
|
93
|
-
getDisplaySpec({ record, selectedRecords, gridModel, column, ...rest }: ActionFnData):
|
|
94
|
-
icon: ReactElement<any, string | import("react").JSXElementConstructor<any>>;
|
|
95
|
-
text: string;
|
|
96
|
-
secondaryText: string;
|
|
97
|
-
intent: Intent;
|
|
98
|
-
className: string;
|
|
99
|
-
tooltip: string;
|
|
100
|
-
items: (string | RecordAction)[];
|
|
101
|
-
hidden: boolean;
|
|
102
|
-
disabled: boolean;
|
|
103
|
-
};
|
|
93
|
+
getDisplaySpec({ record, selectedRecords, gridModel, column, ...rest }: ActionFnData): RecordActionSpec;
|
|
104
94
|
/**
|
|
105
95
|
* Called by UI elements to trigger the action.
|
|
106
96
|
* @internal
|
|
@@ -13,8 +13,8 @@ export declare let agGridVersion: any;
|
|
|
13
13
|
* implementations.
|
|
14
14
|
*/
|
|
15
15
|
export type { GridOptions, GridApi, SortDirection, ColDef, ColGroupDef, GetContextMenuItemsParams, GridReadyEvent, IHeaderGroupParams, IHeaderParams, ProcessCellForExportParams, CellClassParams, HeaderClassParams, HeaderValueGetterParams, ICellRendererParams, ITooltipParams, IRowNode, RowClassParams, ValueGetterParams, ValueSetterParams, MenuItemDef, CellPosition, NavigateToNextCellParams, ColumnEvent, ColumnState as AgColumnState, Column as AgColumn, ColumnGroup as AgColumnGroup, AgProvidedColumnGroup, RowDoubleClickedEvent, RowClickedEvent, RowHeightParams, CellClickedEvent, CellContextMenuEvent, CellDoubleClickedEvent, CellEditingStartedEvent, CellEditingStoppedEvent } from 'ag-grid-community';
|
|
16
|
-
export type { CustomCellEditorProps } from 'ag-grid-react';
|
|
17
|
-
export { useGridCellEditor } from 'ag-grid-react';
|
|
16
|
+
export type { CustomCellEditorProps, CustomMenuItemProps } from 'ag-grid-react';
|
|
17
|
+
export { useGridCellEditor, useGridMenuItem } from 'ag-grid-react';
|
|
18
18
|
/**
|
|
19
19
|
* Expose application versions of ag-Grid to Hoist.
|
|
20
20
|
* Typically called in the Bootstrap.js. of the application.
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
isEmpty,
|
|
19
19
|
isEqual,
|
|
20
20
|
isNil,
|
|
21
|
+
isObject,
|
|
21
22
|
partition,
|
|
22
23
|
setWith,
|
|
23
24
|
startCase
|
|
@@ -415,27 +416,23 @@ export class AgGridModel extends HoistModel {
|
|
|
415
416
|
|
|
416
417
|
const expandState = {};
|
|
417
418
|
this.agApi.forEachNode(node => {
|
|
418
|
-
if (!node.allChildrenCount) return;
|
|
419
|
-
|
|
420
|
-
if
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
) {
|
|
429
|
-
return;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
// Note use of setWith + customizer - required to ensure that nested nodes are
|
|
433
|
-
// serialized as objects - see https://github.com/xh/hoist-react/issues/3550.
|
|
434
|
-
const path = this.getGroupNodePath(node);
|
|
435
|
-
setWith(expandState, path, true, () => ({}));
|
|
419
|
+
if (!node.allChildrenCount || !node.expanded) return;
|
|
420
|
+
// Skip if parent is collapsed. Parents are visited before children,
|
|
421
|
+
// so should already be in expandState if expanded.
|
|
422
|
+
const parent = node.parent;
|
|
423
|
+
if (
|
|
424
|
+
parent &&
|
|
425
|
+
parent.id !== 'ROOT_NODE_ID' &&
|
|
426
|
+
!has(expandState, this.getGroupNodePath(parent))
|
|
427
|
+
) {
|
|
428
|
+
return;
|
|
436
429
|
}
|
|
437
|
-
});
|
|
438
430
|
|
|
431
|
+
const path = this.getGroupNodePath(node);
|
|
432
|
+
// Note use of setWith + customizer - required to ensure that nested nodes are
|
|
433
|
+
// serialized as objects - see https://github.com/xh/hoist-react/issues/3550.
|
|
434
|
+
setWith(expandState, path, true, nsValue => (isObject(nsValue) ? nsValue : {}));
|
|
435
|
+
});
|
|
439
436
|
return expandState;
|
|
440
437
|
}
|
|
441
438
|
|
|
@@ -4,18 +4,22 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Copyright © 2025 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import {isEmpty, isFunction, isNil, isString, uniq} from 'lodash';
|
|
8
|
+
import copy from 'clipboard-copy';
|
|
9
|
+
import {hoistCmp, type HoistProps, type Some, XH} from '@xh/hoist/core';
|
|
8
10
|
import {Column, GridModel} from '@xh/hoist/cmp/grid';
|
|
9
|
-
import {RecordAction, Store, StoreRecord} from '@xh/hoist/data';
|
|
10
|
-
import {
|
|
11
|
+
import {RecordAction, type RecordActionSpec, Store, StoreRecord} from '@xh/hoist/data';
|
|
12
|
+
import {Icon} from '@xh/hoist/icon';
|
|
11
13
|
import {filterConsecutiveMenuSeparators} from '@xh/hoist/utils/impl';
|
|
12
|
-
import copy from 'clipboard-copy';
|
|
13
|
-
import {isEmpty, isFunction, isNil, isString, uniq} from 'lodash';
|
|
14
|
-
import {isValidElement} from 'react';
|
|
15
|
-
import {GridContextMenuItemLike, GridContextMenuSpec} from '../GridContextMenu';
|
|
16
|
-
|
|
17
|
-
import type {GetContextMenuItemsParams, MenuItemDef} from '@xh/hoist/kit/ag-grid';
|
|
18
14
|
import {wait} from '@xh/hoist/promise';
|
|
15
|
+
import {div, span} from '@xh/hoist/cmp/layout';
|
|
16
|
+
import {
|
|
17
|
+
useGridMenuItem,
|
|
18
|
+
type GetContextMenuItemsParams,
|
|
19
|
+
type MenuItemDef,
|
|
20
|
+
type CustomMenuItemProps
|
|
21
|
+
} from '@xh/hoist/kit/ag-grid';
|
|
22
|
+
import type {GridContextMenuItemLike, GridContextMenuSpec} from '../GridContextMenu';
|
|
19
23
|
|
|
20
24
|
/**
|
|
21
25
|
* @internal
|
|
@@ -75,22 +79,22 @@ function buildMenuItems(
|
|
|
75
79
|
subMenu = buildMenuItems(displaySpec.items, record, gridModel, column, agParams);
|
|
76
80
|
}
|
|
77
81
|
|
|
78
|
-
const icon = isValidElement(displaySpec.icon) ? convertIconToHtml(displaySpec.icon) : null;
|
|
79
|
-
|
|
80
82
|
const cssClasses = ['xh-grid-menu-option'];
|
|
81
83
|
if (displaySpec.intent)
|
|
82
84
|
cssClasses.push(`xh-grid-menu-option--intent-${displaySpec.intent}`);
|
|
83
85
|
if (displaySpec.className) cssClasses.push(displaySpec.className);
|
|
84
86
|
|
|
85
87
|
ret.push({
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
88
|
+
menuItem: RecordActionMenuItem,
|
|
89
|
+
menuItemParams: {
|
|
90
|
+
displaySpec
|
|
91
|
+
},
|
|
92
|
+
// Standard MenuActionProps
|
|
89
93
|
cssClasses,
|
|
90
94
|
subMenu,
|
|
91
95
|
tooltip: displaySpec.tooltip,
|
|
92
96
|
disabled: displaySpec.disabled,
|
|
93
|
-
//
|
|
97
|
+
// Don't specify action if no handler, allows submenus to remain open if clicked
|
|
94
98
|
action: action.actionFn ? () => action.call(actionParams) : undefined
|
|
95
99
|
});
|
|
96
100
|
});
|
|
@@ -178,17 +182,16 @@ function replaceHoistToken(token: string, gridModel: GridModel): Some<RecordActi
|
|
|
178
182
|
const values = getValues(selectedRecords, field);
|
|
179
183
|
if (values.length > 1) return {text: `${values.length} values`};
|
|
180
184
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
text = text?.trim();
|
|
185
|
+
const renderer = fieldSpec.renderer ?? column.renderer,
|
|
186
|
+
elem = renderer
|
|
187
|
+
? renderer(values[0], {
|
|
188
|
+
record,
|
|
189
|
+
column,
|
|
190
|
+
gridModel
|
|
191
|
+
})
|
|
192
|
+
: (values[0] ?? '[blank]');
|
|
190
193
|
|
|
191
|
-
return {text:
|
|
194
|
+
return {text: elem};
|
|
192
195
|
};
|
|
193
196
|
|
|
194
197
|
return new RecordAction({
|
|
@@ -297,3 +300,43 @@ function levelExpandAction(gridModel: GridModel): RecordAction {
|
|
|
297
300
|
}
|
|
298
301
|
});
|
|
299
302
|
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* A MenuItem for a Hoist RecordAction.
|
|
306
|
+
*
|
|
307
|
+
* A variant of the standard ag-Grid Context menu. Unlike built-in ag-Grid menu item,
|
|
308
|
+
* provides support for specifying 'text' and 'shortcut' display as react elements.
|
|
309
|
+
*
|
|
310
|
+
* @internal
|
|
311
|
+
*/
|
|
312
|
+
|
|
313
|
+
interface RecordActionMenuItemProps extends HoistProps, CustomMenuItemProps {
|
|
314
|
+
displaySpec: RecordActionSpec;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const RecordActionMenuItem = hoistCmp<RecordActionMenuItemProps>({
|
|
318
|
+
render({displaySpec, subMenu}: RecordActionMenuItemProps) {
|
|
319
|
+
useGridMenuItem({
|
|
320
|
+
configureDefaults: () => true
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
return div(
|
|
324
|
+
span({className: 'ag-menu-option-part ag-menu-option-icon', item: displaySpec.icon}),
|
|
325
|
+
span({className: 'ag-menu-option-part ag-menu-option-text', item: displaySpec.text}),
|
|
326
|
+
span({
|
|
327
|
+
className: 'ag-menu-option-part ag-menu-option-shortcut',
|
|
328
|
+
item: displaySpec.secondaryText
|
|
329
|
+
}),
|
|
330
|
+
span({
|
|
331
|
+
className: 'ag-menu-option-part ag-menu-option-popup-pointer',
|
|
332
|
+
item: subMenu
|
|
333
|
+
? span({
|
|
334
|
+
className: 'ag-icon ag-icon-small-right',
|
|
335
|
+
unselectable: 'on',
|
|
336
|
+
role: 'presentation'
|
|
337
|
+
})
|
|
338
|
+
: ''
|
|
339
|
+
})
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
});
|
package/data/RecordAction.ts
CHANGED
|
@@ -6,17 +6,17 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import {isBoolean, isEmpty, isNil, isNumber, isString} from 'lodash';
|
|
9
|
-
import {ReactElement} from 'react';
|
|
10
|
-
import {Intent,
|
|
9
|
+
import {ReactElement, ReactNode} from 'react';
|
|
10
|
+
import {Intent, TestSupportProps} from '../core';
|
|
11
11
|
import {StoreRecord} from './StoreRecord';
|
|
12
12
|
import {Column, GridModel} from '../cmp/grid';
|
|
13
13
|
|
|
14
14
|
export interface RecordActionSpec extends TestSupportProps {
|
|
15
15
|
/** Label to be displayed. */
|
|
16
|
-
text?:
|
|
16
|
+
text?: ReactNode;
|
|
17
17
|
|
|
18
18
|
/** Additional label to be displayed, usually in a minimal fashion.*/
|
|
19
|
-
secondaryText?:
|
|
19
|
+
secondaryText?: ReactNode;
|
|
20
20
|
|
|
21
21
|
/** Icon to be displayed.*/
|
|
22
22
|
icon?: ReactElement;
|
|
@@ -100,15 +100,15 @@ export interface ActionFnData {
|
|
|
100
100
|
* @see GridContextMenuSpec
|
|
101
101
|
*/
|
|
102
102
|
export class RecordAction {
|
|
103
|
-
text:
|
|
104
|
-
secondaryText:
|
|
103
|
+
text: ReactNode;
|
|
104
|
+
secondaryText: ReactNode;
|
|
105
105
|
icon: ReactElement;
|
|
106
106
|
intent: Intent;
|
|
107
107
|
className: string;
|
|
108
108
|
tooltip: string;
|
|
109
109
|
actionFn: (data: ActionFnData) => void;
|
|
110
|
-
displayFn: (data: ActionFnData) =>
|
|
111
|
-
items:
|
|
110
|
+
displayFn: (data: ActionFnData) => RecordActionSpec;
|
|
111
|
+
items: RecordActionLike[];
|
|
112
112
|
disabled: boolean;
|
|
113
113
|
hidden: boolean;
|
|
114
114
|
recordsRequired: boolean | number;
|
|
@@ -152,11 +152,17 @@ export class RecordAction {
|
|
|
152
152
|
* Called by UI elements to get the display configuration for rendering the action.
|
|
153
153
|
* @internal
|
|
154
154
|
*/
|
|
155
|
-
getDisplaySpec({
|
|
155
|
+
getDisplaySpec({
|
|
156
|
+
record,
|
|
157
|
+
selectedRecords,
|
|
158
|
+
gridModel,
|
|
159
|
+
column,
|
|
160
|
+
...rest
|
|
161
|
+
}: ActionFnData): RecordActionSpec {
|
|
156
162
|
const recordCount =
|
|
157
163
|
record && isEmpty(selectedRecords) ? 1 : selectedRecords ? selectedRecords.length : 0;
|
|
158
164
|
|
|
159
|
-
const defaultDisplay = {
|
|
165
|
+
const defaultDisplay: RecordActionSpec = {
|
|
160
166
|
icon: this.icon,
|
|
161
167
|
text: this.text,
|
|
162
168
|
secondaryText: this.secondaryText,
|
package/kit/ag-grid/index.ts
CHANGED
|
@@ -60,8 +60,8 @@ export type {
|
|
|
60
60
|
CellEditingStoppedEvent
|
|
61
61
|
} from 'ag-grid-community';
|
|
62
62
|
|
|
63
|
-
export type {CustomCellEditorProps} from 'ag-grid-react';
|
|
64
|
-
export {useGridCellEditor} from 'ag-grid-react';
|
|
63
|
+
export type {CustomCellEditorProps, CustomMenuItemProps} from 'ag-grid-react';
|
|
64
|
+
export {useGridCellEditor, useGridMenuItem} from 'ag-grid-react';
|
|
65
65
|
|
|
66
66
|
const MIN_VERSION = '34.2.0';
|
|
67
67
|
const MAX_VERSION = '34.*.*';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xh/hoist",
|
|
3
|
-
"version": "77.0.0-SNAPSHOT.
|
|
3
|
+
"version": "77.0.0-SNAPSHOT.1761769225395",
|
|
4
4
|
"description": "Hoist add-on for building and deploying React Applications.",
|
|
5
5
|
"repository": "github:xh/hoist-react",
|
|
6
6
|
"homepage": "https://xh.io",
|