@xh/hoist 76.0.0-SNAPSHOT.1758755408459 → 76.0.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Changelog
2
2
 
3
- ## 76.0.0-SNAPSHOT - unreleased
3
+ ## 76.0.0 - 2025-09-26
4
4
 
5
5
  ### 💥 Breaking Changes (upgrade difficulty: 🟠 MEDIUM - AG Grid update, Hoist React upgrade)
6
6
 
@@ -44,9 +44,10 @@
44
44
  * New constraint rule: `validEmails` - to validate one or more email addresses in an input field.
45
45
  * `DashCanvas` accepts a new prop `rglOptions` to pass additional options to the underlying
46
46
  `react-grid-layout`.
47
- * * Experimental grid feature `enableFullWidthScroll` has been promoted to a first-class property
47
+ * Experimental grid feature `enableFullWidthScroll` has been promoted to a first-class property
48
48
  on `GridModel`. Set to true to ensure that the grid will have a single horizontal scrollbar
49
49
  spanning the width of all columns, including any pinned columns.
50
+ * New `@sharePendingPromise` decorator for returning a shared Promise across concurrent async calls.
50
51
 
51
52
 
52
53
  ### 🐞 Bug Fixes
@@ -56,6 +57,10 @@
56
57
  its configured `initialViewSpec` function as expected in this case.
57
58
  * Updated `XH.restoreDefaultsAsync` to clear basic view state, including the user's last selected
58
59
  view. Views themselves will be preserved. Requires `hoist-core >= 32.0`.
60
+ * Fixed bug where `GridModel.persistableColumnState` was not including default column `widths`.
61
+ This led to columns not being set to their expected widths when switching `ViewManager` views.
62
+ * Fixed bug where a `Grid` with managed autosizing was not triggering an autosize as expected when
63
+ new column state was loaded (e.g. via `ViewManager`).
59
64
 
60
65
  ### ⚙️ Technical
61
66
 
@@ -463,7 +463,6 @@ export declare class GridModel extends HoistModel {
463
463
  updateData(rawData: PlainObject[] | StoreTransaction): import("@xh/hoist/data").StoreChangeLog;
464
464
  /** Clear the underlying store, removing all rows. */
465
465
  clear(): void;
466
- /** @param colConfigs - {@link Column} or {@link ColumnGroup} configs. */
467
466
  setColumns(colConfigs: Array<ColumnSpec | ColumnGroupSpec>): void;
468
467
  setColumnState(colState: Partial<ColumnState>[]): void;
469
468
  showColChooser(): void;
@@ -17,7 +17,7 @@ export declare class ColumnWidthCalculator {
17
17
  private _headerEl;
18
18
  private _cellEl;
19
19
  private _rowEl;
20
- calcWidthAsync(gridModel: GridModel, records: StoreRecord[], colId: string, options: GridAutosizeOptions): Promise<any>;
20
+ calcWidthAsync(gridModel: GridModel, records: StoreRecord[], colId: string, options: Omit<GridAutosizeOptions, 'columns'>): Promise<any>;
21
21
  calcHeaderWidth(gridModel: any, column: any, options: any): any;
22
22
  calcDataWidthAsync(gridModel: any, records: any, column: any, options: any): Promise<number>;
23
23
  calcLevelWidthAsync(gridModel: any, records: any, column: any, options: any, indentationPx?: number): Promise<number>;
@@ -23,7 +23,7 @@ export declare class GridAutosizeService extends HoistService {
23
23
  * @param colIds - array of columns in model to compute sizing for.
24
24
  * @param options - options to use for this autosize.
25
25
  */
26
- autosizeAsync(gridModel: GridModel, colIds: string[], options: GridAutosizeOptions): Promise<void>;
26
+ autosizeAsync(gridModel: GridModel, colIds: string[], options: Omit<GridAutosizeOptions, 'columns'>): Promise<void>;
27
27
  private calcRequiredWidthsAsync;
28
28
  private gatherRecordsToBeSized;
29
29
  private calcFillWidths;
@@ -28,3 +28,15 @@ export declare function enumerable(target: any, key: any, descriptor: any): any;
28
28
  * Designate a method or getter as abstract so that it throws if it is called directly
29
29
  */
30
30
  export declare function abstract(target: any, key: any, descriptor: any): any;
31
+ /**
32
+ * Decorates a class method that returns a Promise so that concurrent calls with the same arguments
33
+ * will share a single pending Promise. Arguments must be serializable via JSON.stringify.
34
+ */
35
+ export declare function sharePendingPromise<T>(target: T, key: string, descriptor: PropertyDescriptor): {
36
+ value: () => any;
37
+ configurable?: boolean;
38
+ enumerable?: boolean;
39
+ writable?: boolean;
40
+ get?(): any;
41
+ set?(v: any): void;
42
+ };
@@ -61,6 +61,7 @@ import {wait, waitFor} from '@xh/hoist/promise';
61
61
  import {ExportOptions} from '@xh/hoist/svc/GridExportService';
62
62
  import {SECONDS} from '@xh/hoist/utils/datetime';
63
63
  import {
64
+ sharePendingPromise,
64
65
  deepFreeze,
65
66
  executeIfFunction,
66
67
  logWithDebug,
@@ -1137,7 +1138,6 @@ export class GridModel extends HoistModel {
1137
1138
  this.store.clear();
1138
1139
  }
1139
1140
 
1140
- /** @param colConfigs - {@link Column} or {@link ColumnGroup} configs. */
1141
1141
  @action
1142
1142
  setColumns(colConfigs: Array<ColumnSpec | ColumnGroupSpec>) {
1143
1143
  this.validateColConfigs(colConfigs);
@@ -1147,10 +1147,15 @@ export class GridModel extends HoistModel {
1147
1147
  this.validateColumns(columns);
1148
1148
 
1149
1149
  this.columns = columns;
1150
- this.columnState = this.getLeafColumns().map(it => {
1151
- const {colId, width, hidden, pinned} = it;
1152
- return {colId, width, hidden, pinned};
1153
- });
1150
+ this.columnState = this.getLeafColumns().map(it => ({
1151
+ ...pick(it, ['colId', 'width', 'hidden', 'pinned']),
1152
+ // If not in managed auto-size mode, treat in-code column widths as manuallySized so
1153
+ // widths are not omitted from persistableColumnState. This is important because
1154
+ // PersistanceProvider.getPersistableState() expects a complete snapshot of initial
1155
+ // state in order to detect changes and restore initial state correctly.
1156
+ // See https://github.com/xh/hoist-react/issues/4102.
1157
+ manuallySized: !!(it.width && this.autosizeOptions.mode !== 'managed')
1158
+ }));
1154
1159
  }
1155
1160
 
1156
1161
  setColumnState(colState: Partial<ColumnState>[]) {
@@ -1373,14 +1378,16 @@ export class GridModel extends HoistModel {
1373
1378
  */
1374
1379
  @logWithDebug
1375
1380
  async autosizeAsync(overrideOpts: Omit<GridAutosizeOptions, 'mode'> = {}) {
1376
- const options: GridAutosizeOptions = {...this.autosizeOptions, ...overrideOpts};
1381
+ const {columns, ...options}: GridAutosizeOptions = {
1382
+ ...this.autosizeOptions,
1383
+ ...overrideOpts
1384
+ };
1377
1385
 
1378
1386
  if (options.mode === 'disabled') {
1379
1387
  return;
1380
1388
  }
1381
1389
 
1382
1390
  // 1) Pre-process columns to be operated on
1383
- const {columns} = options;
1384
1391
  if (columns) options.fillMode = 'none'; // Fill makes sense only for the entire set.
1385
1392
 
1386
1393
  let colIds: string[],
@@ -1577,7 +1584,11 @@ export class GridModel extends HoistModel {
1577
1584
  return new Column(config, this);
1578
1585
  }
1579
1586
 
1580
- private async autosizeColsInternalAsync(colIds: string[], options: GridAutosizeOptions) {
1587
+ @sharePendingPromise
1588
+ private async autosizeColsInternalAsync(
1589
+ colIds: string[],
1590
+ options: Omit<GridAutosizeOptions, 'columns'>
1591
+ ) {
1581
1592
  await this.whenReadyAsync();
1582
1593
  if (!this.isReady) return;
1583
1594
 
@@ -50,7 +50,7 @@ export class ColumnWidthCalculator {
50
50
  gridModel: GridModel,
51
51
  records: StoreRecord[],
52
52
  colId: string,
53
- options: GridAutosizeOptions
53
+ options: Omit<GridAutosizeOptions, 'columns'>
54
54
  ) {
55
55
  const column = gridModel.findColumn(gridModel.columns, colId),
56
56
  {autosizeMinWidth, autosizeMaxWidth} = column;
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import {PersistableState, PersistenceProvider} from '@xh/hoist/core';
8
8
  import {isEqual, isObject} from 'lodash';
9
+ import {runInAction} from 'mobx';
9
10
  import {GridModel} from '../GridModel';
10
11
  import {ColumnState, GridModelPersistOptions} from '../Types';
11
12
 
@@ -36,7 +37,18 @@ export function initPersist(
36
37
  target: {
37
38
  getPersistableState: () =>
38
39
  new PersistableColumnState(gridModel.persistableColumnState),
39
- setPersistableState: ({value}) => gridModel.setColumnState(value)
40
+ setPersistableState: ({value}) =>
41
+ runInAction(() => {
42
+ // Set columnState directly since GridModel.setColumnState will merge the
43
+ // provided state with the current state, which is not what we want here.
44
+ gridModel.columnState = gridModel.cleanColumnState(value);
45
+ if (gridModel.autosizeOptions.mode === 'managed') {
46
+ const columns = gridModel.columnState
47
+ .filter(it => !it.manuallySized)
48
+ .map(it => it.colId);
49
+ gridModel.autosizeAsync({columns});
50
+ }
51
+ })
40
52
  },
41
53
  owner: gridModel
42
54
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xh/hoist",
3
- "version": "76.0.0-SNAPSHOT.1758755408459",
3
+ "version": "76.0.0",
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",
@@ -38,7 +38,11 @@ export class GridAutosizeService extends HoistService {
38
38
  * @param colIds - array of columns in model to compute sizing for.
39
39
  * @param options - options to use for this autosize.
40
40
  */
41
- async autosizeAsync(gridModel: GridModel, colIds: string[], options: GridAutosizeOptions) {
41
+ async autosizeAsync(
42
+ gridModel: GridModel,
43
+ colIds: string[],
44
+ options: Omit<GridAutosizeOptions, 'columns'>
45
+ ) {
42
46
  await gridModel.whenReadyAsync();
43
47
  if (!gridModel.isReady) return;
44
48
 
@@ -103,7 +107,7 @@ export class GridAutosizeService extends HoistService {
103
107
  gridModel: GridModel,
104
108
  colIds: string[],
105
109
  records: StoreRecord[],
106
- options: GridAutosizeOptions,
110
+ options: Omit<GridAutosizeOptions, 'columns'>,
107
111
  manuallySized: boolean
108
112
  ): Promise<ColWidthSpec[]> {
109
113
  const startRecords = gridModel.store._filtered,
@@ -127,7 +131,7 @@ export class GridAutosizeService extends HoistService {
127
131
 
128
132
  private gatherRecordsToBeSized(
129
133
  gridModel: GridModel,
130
- options: GridAutosizeOptions
134
+ options: Omit<GridAutosizeOptions, 'columns'>
131
135
  ): StoreRecord[] {
132
136
  let {store, agApi, treeMode, groupBy} = gridModel,
133
137
  {includeCollapsedChildren, renderedRowsOnly} = options,