@xh/hoist 76.0.0-SNAPSHOT.1758310971360 → 76.0.0-SNAPSHOT.1758570404363

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.
Files changed (35) hide show
  1. package/CHANGELOG.md +20 -1
  2. package/admin/tabs/userData/roles/details/members/BaseMembersModel.ts +2 -2
  3. package/build/types/admin/tabs/userData/roles/details/members/BaseMembersModel.d.ts +2 -2
  4. package/build/types/cmp/dataview/DataViewModel.d.ts +1 -1
  5. package/build/types/cmp/grid/Grid.d.ts +4 -4
  6. package/build/types/cmp/grid/GridModel.d.ts +16 -6
  7. package/build/types/cmp/grid/Types.d.ts +1 -2
  8. package/build/types/cmp/grid/columns/Column.d.ts +1 -2
  9. package/build/types/cmp/grid/impl/ColumnGroupHeader.d.ts +3 -3
  10. package/build/types/cmp/zoneGrid/ZoneGridModel.d.ts +1 -1
  11. package/build/types/desktop/cmp/grid/editors/EditorProps.d.ts +1 -1
  12. package/build/types/desktop/cmp/rest/RestGridModel.d.ts +1 -1
  13. package/build/types/kit/ag-grid/index.d.ts +5 -2
  14. package/cmp/ag-grid/AgGrid.ts +0 -1
  15. package/cmp/ag-grid/AgGridModel.ts +9 -60
  16. package/cmp/dataview/DataViewModel.ts +1 -1
  17. package/cmp/grid/Grid.ts +31 -20
  18. package/cmp/grid/GridModel.ts +46 -18
  19. package/cmp/grid/Types.ts +2 -2
  20. package/cmp/grid/columns/Column.ts +3 -3
  21. package/cmp/grid/impl/ColumnGroupHeader.ts +5 -3
  22. package/cmp/grid/impl/ColumnHeader.ts +2 -3
  23. package/cmp/grid/impl/MenuSupport.ts +2 -1
  24. package/cmp/zoneGrid/ZoneGrid.ts +1 -2
  25. package/cmp/zoneGrid/ZoneGridModel.ts +1 -1
  26. package/desktop/cmp/grid/editors/BooleanEditor.ts +1 -1
  27. package/desktop/cmp/grid/editors/DateEditor.ts +2 -7
  28. package/desktop/cmp/grid/editors/EditorProps.ts +1 -1
  29. package/desktop/cmp/grid/editors/NumberEditor.ts +1 -1
  30. package/desktop/cmp/grid/editors/impl/InlineEditorModel.ts +2 -2
  31. package/desktop/cmp/rest/RestGridModel.ts +1 -1
  32. package/inspector/instances/InstancesPanel.ts +1 -2
  33. package/kit/ag-grid/index.ts +20 -5
  34. package/package.json +3 -4
  35. package/tsconfig.tsbuildinfo +1 -1
@@ -8,11 +8,13 @@ import {
8
8
  CellClickedEvent,
9
9
  CellContextMenuEvent,
10
10
  CellDoubleClickedEvent,
11
+ CellEditingStartedEvent,
12
+ CellEditingStoppedEvent,
11
13
  ColumnEvent,
12
- ColumnState as AgColumnState,
14
+ AgColumnState,
13
15
  RowClickedEvent,
14
16
  RowDoubleClickedEvent
15
- } from '@ag-grid-community/core';
17
+ } from '@xh/hoist/kit/ag-grid';
16
18
  import {AgGridModel} from '@xh/hoist/cmp/ag-grid';
17
19
  import {
18
20
  Column,
@@ -95,7 +97,7 @@ import {
95
97
  pull,
96
98
  take
97
99
  } from 'lodash';
98
- import {ReactNode} from 'react';
100
+ import {createRef, ReactNode, RefObject} from 'react';
99
101
  import {GridAutosizeOptions} from './GridAutosizeOptions';
100
102
  import {GridContextMenuSpec} from './GridContextMenu';
101
103
  import {GridSorter, GridSorterLike} from './GridSorter';
@@ -341,6 +343,13 @@ export interface GridConfig {
341
343
  */
342
344
  highlightRowOnClick?: boolean;
343
345
 
346
+ /**
347
+ * Set to true to ensure that the grid will have a single horizontal scrollbar spanning the
348
+ * width of all columns, including any pinned columns. A value of false (default) will show
349
+ * the scrollbar only under the scrollable area.
350
+ */
351
+ enableFullWidthScroll?: boolean;
352
+
344
353
  /**
345
354
  * Flags for experimental features. These features are designed for early client-access and
346
355
  * testing, but are not yet part of the Hoist API.
@@ -393,6 +402,7 @@ export class GridModel extends HoistModel {
393
402
  showGroupRowCounts: boolean;
394
403
  enableColumnPinning: boolean;
395
404
  enableExport: boolean;
405
+ enableFullWidthScroll: boolean;
396
406
  externalSort: boolean;
397
407
  exportOptions: ExportOptions;
398
408
  useVirtualColumns: boolean;
@@ -419,6 +429,7 @@ export class GridModel extends HoistModel {
419
429
 
420
430
  @managed filterModel: GridFilterModel;
421
431
  @managed agGridModel: AgGridModel;
432
+ viewRef: RefObject<HTMLDivElement> = createRef();
422
433
 
423
434
  //------------------------
424
435
  // Observable API
@@ -442,7 +453,9 @@ export class GridModel extends HoistModel {
442
453
  * Flag to track inline editing at a granular level. Will toggle each time row
443
454
  * or cell editing is activated or ended.
444
455
  */
445
- @observable isEditing = false;
456
+ get isEditing(): boolean {
457
+ return !!this.editingCell;
458
+ }
446
459
 
447
460
  /**
448
461
  * Flag to track inline editing at a general level.
@@ -469,7 +482,7 @@ export class GridModel extends HoistModel {
469
482
  'colChooser',
470
483
  'autosizeColumns'
471
484
  ];
472
-
485
+ @observable.ref private editingCell: {colId: string; rowIndex: number} = null;
473
486
  private _defaultState; // initial state provided to ctor - powers restoreDefaults().
474
487
 
475
488
  /**
@@ -485,6 +498,10 @@ export class GridModel extends HoistModel {
485
498
  return treeMode ? store.maxDepth : groupBy ? groupBy.length : 0;
486
499
  }
487
500
 
501
+ get bodyViewport(): HTMLElement {
502
+ return this.viewRef.current?.querySelector('.ag-body-viewport') as HTMLElement;
503
+ }
504
+
488
505
  /** Tracks execution of filtering operations.*/
489
506
  @managed filterTask = TaskObserver.trackAll();
490
507
 
@@ -545,6 +562,7 @@ export class GridModel extends HoistModel {
545
562
  expandLevel = treeMode ? 0 : 1,
546
563
  levelLabels,
547
564
  highlightRowOnClick = XH.isMobileApp,
565
+ enableFullWidthScroll = false,
548
566
  experimental,
549
567
  appData,
550
568
  xhImpl,
@@ -571,6 +589,7 @@ export class GridModel extends HoistModel {
571
589
  contextMenu === false ? [] : withDefault(contextMenu, GridModel.defaultContextMenu);
572
590
  this.useVirtualColumns = useVirtualColumns;
573
591
  this.externalSort = externalSort;
592
+ this.enableFullWidthScroll = enableFullWidthScroll;
574
593
  this.autosizeOptions = defaults(
575
594
  {...autosizeOptions},
576
595
  {
@@ -1216,7 +1235,7 @@ export class GridModel extends HoistModel {
1216
1235
 
1217
1236
  // 1) Update any width, visibility or pinned changes
1218
1237
  colStateChanges.forEach(change => {
1219
- const col = find(columnState, {colId: change.colId});
1238
+ const col: ColumnState = find(columnState, {colId: change.colId});
1220
1239
 
1221
1240
  if (!isNil(change.width)) col.width = change.width;
1222
1241
  if (!isNil(change.hidden)) col.hidden = change.hidden;
@@ -1354,7 +1373,7 @@ export class GridModel extends HoistModel {
1354
1373
  */
1355
1374
  @logWithDebug
1356
1375
  async autosizeAsync(overrideOpts: Omit<GridAutosizeOptions, 'mode'> = {}) {
1357
- const options = {...this.autosizeOptions, ...overrideOpts};
1376
+ const options: GridAutosizeOptions = {...this.autosizeOptions, ...overrideOpts};
1358
1377
 
1359
1378
  if (options.mode === 'disabled') {
1360
1379
  return;
@@ -1464,14 +1483,27 @@ export class GridModel extends HoistModel {
1464
1483
 
1465
1484
  /** @internal */
1466
1485
  @action
1467
- onCellEditingStarted = () => {
1468
- this.isEditing = true;
1486
+ onCellEditingStarted = (e: CellEditingStartedEvent) => {
1487
+ this.editingCell = {colId: e.column.getColId(), rowIndex: e.rowIndex};
1469
1488
  };
1470
1489
 
1471
1490
  /** @internal*/
1472
1491
  @action
1473
- onCellEditingStopped = () => {
1474
- this.isEditing = false;
1492
+ onCellEditingStopped = (e: CellEditingStoppedEvent) => {
1493
+ const origCell = this.editingCell;
1494
+ this.editingCell = null;
1495
+ const {agApi} = this,
1496
+ focusedCell = agApi.getFocusedCell();
1497
+
1498
+ // If the rowIndex has moved since we started edit, sorting might have caused the wrong row
1499
+ // to be focused. In this (rare) case, just conservatively keep focus on what was edited
1500
+ if (
1501
+ !isUndefined(e.rowIndex) &&
1502
+ origCell?.rowIndex != e.rowIndex &&
1503
+ focusedCell?.rowIndex != e.rowIndex
1504
+ ) {
1505
+ agApi.setFocusedCell(e.rowIndex, origCell.colId);
1506
+ }
1475
1507
  };
1476
1508
 
1477
1509
  /**
@@ -1547,11 +1579,11 @@ export class GridModel extends HoistModel {
1547
1579
  await this.whenReadyAsync();
1548
1580
  if (!this.isReady) return;
1549
1581
 
1550
- const {agApi, empty} = this,
1582
+ const {agApi} = this,
1551
1583
  {showMask} = options;
1552
1584
 
1553
1585
  if (showMask) {
1554
- agApi.showLoadingOverlay();
1586
+ agApi.updateGridOptions({loading: true});
1555
1587
  }
1556
1588
 
1557
1589
  try {
@@ -1559,11 +1591,7 @@ export class GridModel extends HoistModel {
1559
1591
  } finally {
1560
1592
  if (showMask) {
1561
1593
  await wait();
1562
- if (empty) {
1563
- agApi.showNoRowsOverlay();
1564
- } else {
1565
- agApi.hideOverlay();
1566
- }
1594
+ agApi.updateGridOptions({loading: false});
1567
1595
  }
1568
1596
  }
1569
1597
  }
package/cmp/grid/Types.ts CHANGED
@@ -5,7 +5,6 @@
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
7
 
8
- import {CustomCellEditorProps} from '@ag-grid-community/react';
9
8
  import {GridFilterFieldSpecConfig} from '@xh/hoist/cmp/grid/filter/GridFilterFieldSpec';
10
9
  import {HSide, PersistOptions, Some} from '@xh/hoist/core';
11
10
  import {Store, StoreRecord, View} from '@xh/hoist/data';
@@ -22,7 +21,8 @@ import type {
22
21
  IRowNode,
23
22
  ITooltipParams,
24
23
  RowClassParams,
25
- ValueSetterParams
24
+ ValueSetterParams,
25
+ CustomCellEditorProps
26
26
  } from '@xh/hoist/kit/ag-grid';
27
27
 
28
28
  export interface ColumnState {
@@ -4,7 +4,6 @@
4
4
  *
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
- import {CustomCellEditorProps} from '@ag-grid-community/react';
8
7
  import {div, li, span, ul} from '@xh/hoist/cmp/layout';
9
8
  import {HAlign, HSide, PlainObject, Some, XH, Thunkable} from '@xh/hoist/core';
10
9
  import {
@@ -69,9 +68,10 @@ import type {
69
68
  ColDef,
70
69
  ITooltipParams,
71
70
  ValueGetterParams,
72
- ValueSetterParams
71
+ ValueSetterParams,
72
+ CustomCellEditorProps,
73
+ CellClickedEvent
73
74
  } from '@xh/hoist/kit/ag-grid';
74
- import {CellClickedEvent} from '@ag-grid-community/core';
75
75
 
76
76
  export interface ColumnSpec {
77
77
  /**
@@ -13,7 +13,7 @@ import classNames from 'classnames';
13
13
  import {isFunction} from 'lodash';
14
14
  import {ReactNode} from 'react';
15
15
 
16
- import type {AgColumnGroup, IHeaderGroupParams} from '@xh/hoist/kit/ag-grid';
16
+ import type {AgProvidedColumnGroup, IHeaderGroupParams} from '@xh/hoist/kit/ag-grid';
17
17
 
18
18
  export interface ColumnGroupHeaderProps
19
19
  extends HoistProps<ColumnGroupHeaderModel>,
@@ -80,7 +80,7 @@ class ColumnGroupHeaderModel extends HoistModel {
80
80
  return this.agColumnGroup.isExpandable();
81
81
  }
82
82
 
83
- get agColumnGroup(): AgColumnGroup {
83
+ get agColumnGroup(): AgProvidedColumnGroup {
84
84
  return this.componentProps.columnGroup.providedColumnGroup;
85
85
  }
86
86
 
@@ -99,5 +99,7 @@ class ColumnGroupHeaderModel extends HoistModel {
99
99
  super.destroy();
100
100
  }
101
101
 
102
- syncIsExpanded = () => (this.isExpanded = this.agColumnGroup.isExpanded());
102
+ syncIsExpanded = () => {
103
+ this.isExpanded = this.agColumnGroup.isExpanded();
104
+ };
103
105
  }
@@ -11,7 +11,7 @@ import {Column, GridModel} from '@xh/hoist/cmp/grid';
11
11
  import {Icon} from '@xh/hoist/icon';
12
12
  import {columnHeaderFilter, ColumnHeaderFilterModel} from '@xh/hoist/dynamics/desktop';
13
13
  import {createObservableRef} from '@xh/hoist/utils/react';
14
- import {debounced} from '@xh/hoist/utils/js';
14
+ import {debounced, consumeEvent} from '@xh/hoist/utils/js';
15
15
  import {olderThan} from '@xh/hoist/utils/datetime';
16
16
  import {
17
17
  filter,
@@ -253,8 +253,7 @@ class ColumnHeaderModel extends HoistModel {
253
253
  onExpandOrCollapse = e => {
254
254
  const {gridModel, majorityIsExpanded} = this;
255
255
 
256
- e.stopPropagation();
257
- e.preventDefault();
256
+ consumeEvent(e);
258
257
  if (majorityIsExpanded) {
259
258
  gridModel.collapseAll();
260
259
  } else {
@@ -16,6 +16,7 @@ import {renderToStaticMarkup} from '@xh/hoist/utils/react';
16
16
  import {GridContextMenuItemLike, GridContextMenuSpec} from '../GridContextMenu';
17
17
 
18
18
  import type {GetContextMenuItemsParams, MenuItemDef} from '@xh/hoist/kit/ag-grid';
19
+ import {wait} from '@xh/hoist/promise';
19
20
 
20
21
  /**
21
22
  * @internal
@@ -294,7 +295,7 @@ function levelExpandAction(gridModel: GridModel): RecordAction {
294
295
  return {
295
296
  icon: isCurrLevel ? Icon.check() : null,
296
297
  text: label,
297
- actionFn: () => gridModel.expandToLevel(idx)
298
+ actionFn: () => wait().then(() => gridModel.expandToLevel(idx))
298
299
  };
299
300
  });
300
301
  return {items};
@@ -52,8 +52,7 @@ export const [ZoneGrid, zoneGrid] = hoistCmp.withFactory<ZoneGridProps>({
52
52
  ref,
53
53
  model: gridModel,
54
54
  agOptions: {
55
- suppressRowGroupHidesColumns: true,
56
- suppressMakeColumnVisibleAfterUnGroup: true,
55
+ suppressGroupChangesColumnVisibility: true,
57
56
  ...props.agOptions
58
57
  }
59
58
  }),
@@ -10,7 +10,7 @@ import {
10
10
  CellDoubleClickedEvent,
11
11
  RowClickedEvent,
12
12
  RowDoubleClickedEvent
13
- } from '@ag-grid-community/core';
13
+ } from '@xh/hoist/kit/ag-grid';
14
14
  import {
15
15
  Column,
16
16
  ColumnRenderer,
@@ -5,7 +5,7 @@
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
7
  import {useEffect} from 'react';
8
- import {CustomCellEditorProps} from '@ag-grid-community/react';
8
+ import {CustomCellEditorProps} from '@xh/hoist/kit/ag-grid';
9
9
  import {hoistCmp} from '@xh/hoist/core';
10
10
  import {checkbox, CheckboxProps} from '@xh/hoist/desktop/cmp/input';
11
11
  import '@xh/hoist/desktop/register';
@@ -23,13 +23,8 @@ export const [DateEditor, dateEditor] = hoistCmp.withFactory<DateEditorProps>({
23
23
  // We need to render the day picker popover inside the grid viewport in order for
24
24
  // `stopEditingWhenCellsLoseFocus` to work properly - otherwise the day picker becomes
25
25
  // unusable due to the grid losing focus and stopping editing when clicking inside picker
26
- // @ts-ignore -- private
27
- const portalContainer = props.gridModel.agApi.gridBodyCtrl?.eBodyViewport;
28
-
29
- warnIf(
30
- !portalContainer,
31
- 'Could not find the grid body viewport for rendering DateEditor picker popover.'
32
- );
26
+ const portalContainer = props.gridModel.bodyViewport;
27
+ warnIf(!portalContainer, 'Could not find the grid viewport for rendering DateEditor');
33
28
 
34
29
  props = {
35
30
  ...props,
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
- import {CustomCellEditorProps} from '@ag-grid-community/react';
7
+ import {CustomCellEditorProps} from '@xh/hoist/kit/ag-grid';
8
8
  import {Column, GridModel} from '@xh/hoist/cmp/grid';
9
9
  import {HoistInputProps} from '@xh/hoist/cmp/input';
10
10
  import {HoistProps} from '@xh/hoist/core';
@@ -7,7 +7,7 @@
7
7
  import {withDefault} from '@xh/hoist/utils/js';
8
8
  import {isNil} from 'lodash';
9
9
  import {useCallback, useEffect} from 'react';
10
- import {CustomCellEditorProps, useGridCellEditor} from '@ag-grid-community/react';
10
+ import {CustomCellEditorProps, useGridCellEditor} from '@xh/hoist/kit/ag-grid';
11
11
  import {hoistCmp} from '@xh/hoist/core';
12
12
  import {numberInput, NumberInputProps} from '@xh/hoist/desktop/cmp/input';
13
13
  import '@xh/hoist/desktop/register';
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
- import {CustomCellEditorProps, useGridCellEditor} from '@ag-grid-community/react';
7
+ import {CustomCellEditorProps, useGridCellEditor} from '@xh/hoist/kit/ag-grid';
8
8
  import composeRefs from '@seznam/compose-react-refs';
9
9
  import {HoistInputModel} from '@xh/hoist/cmp/input';
10
10
  import {ElementFactory, HoistModel, useLocalModel} from '@xh/hoist/core';
@@ -52,7 +52,7 @@ export function useInlineEditorModel(
52
52
  // Call the onCommit callback last - if provided by the app developer.
53
53
  // If app's onCommit invokes agParams.stopEditing() before onValueChange is called,
54
54
  // it will prevent the value change.
55
- props.inputProps?.onCommit?.(value, oldValue);
55
+ inputProps?.onCommit?.(value, oldValue);
56
56
  }
57
57
  });
58
58
  }
@@ -5,7 +5,7 @@
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
7
 
8
- import {RowDoubleClickedEvent} from '@ag-grid-community/core';
8
+ import {RowDoubleClickedEvent} from '@xh/hoist/kit/ag-grid';
9
9
  import {BaseFieldConfig} from '@xh/hoist/cmp/form';
10
10
  import {GridConfig, GridModel} from '@xh/hoist/cmp/grid';
11
11
  import {ElementSpec, HoistModel, managed, PlainObject, XH} from '@xh/hoist/core';
@@ -62,8 +62,7 @@ export const instancesPanel = hoistCmp.factory({
62
62
  item: grid({
63
63
  model: model.instancesGridModel,
64
64
  agOptions: {
65
- suppressRowGroupHidesColumns: true,
66
- suppressMakeColumnVisibleAfterUnGroup: true
65
+ suppressGroupChangesColumnVisibility: true
67
66
  }
68
67
  }),
69
68
  bbar: instanceGridBar(),
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import {checkVersion, logError} from '@xh/hoist/utils/js';
9
+ import {Component} from 'react';
9
10
 
10
11
  /**
11
12
  * The exports below are ag-Grid components provided at runtime by applications.
@@ -44,18 +45,32 @@ export type {
44
45
  MenuItemDef,
45
46
  CellPosition,
46
47
  NavigateToNextCellParams,
48
+ ColumnEvent,
49
+ ColumnState as AgColumnState,
47
50
  Column as AgColumn,
48
- ColumnGroup as AgColumnGroup
49
- } from '@ag-grid-community/core';
51
+ ColumnGroup as AgColumnGroup,
52
+ AgProvidedColumnGroup,
53
+ RowDoubleClickedEvent,
54
+ RowClickedEvent,
55
+ RowHeightParams,
56
+ CellClickedEvent,
57
+ CellContextMenuEvent,
58
+ CellDoubleClickedEvent,
59
+ CellEditingStartedEvent,
60
+ CellEditingStoppedEvent
61
+ } from 'ag-grid-community';
50
62
 
51
- const MIN_VERSION = '31.2.0';
52
- const MAX_VERSION = '31.*.*';
63
+ export type {CustomCellEditorProps} from 'ag-grid-react';
64
+ export {useGridCellEditor} from 'ag-grid-react';
65
+
66
+ const MIN_VERSION = '34.1.1';
67
+ const MAX_VERSION = '34.*.*';
53
68
 
54
69
  /**
55
70
  * Expose application versions of ag-Grid to Hoist.
56
71
  * Typically called in the Bootstrap.js. of the application.
57
72
  */
58
- export function installAgGrid(ComponentReactWrapper, version: string) {
73
+ export function installAgGrid(ComponentReactWrapper: Component, version: string) {
59
74
  if (!checkVersion(version, MIN_VERSION, MAX_VERSION)) {
60
75
  logError(
61
76
  `This version of Hoist requires an ag-Grid version between ${MIN_VERSION} and ` +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xh/hoist",
3
- "version": "76.0.0-SNAPSHOT.1758310971360",
3
+ "version": "76.0.0-SNAPSHOT.1758570404363",
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",
@@ -91,13 +91,12 @@
91
91
  "react-dom": "~18.2.0"
92
92
  },
93
93
  "devDependencies": {
94
- "@ag-grid-community/client-side-row-model": "31.x",
95
- "@ag-grid-community/core": "31.x",
96
- "@ag-grid-community/react": "31.x",
97
94
  "@types/react": "18.x",
98
95
  "@types/react-dom": "18.x",
99
96
  "@types/react-grid-layout": "1.3.5",
100
97
  "@xh/hoist-dev-utils": "11.x",
98
+ "ag-grid-community": "34.x",
99
+ "ag-grid-react": "34.x",
101
100
  "csstype": "3.x",
102
101
  "eslint": "9.x",
103
102
  "eslint-config-prettier": "10.x",