@xh/hoist 80.0.0-SNAPSHOT.1768360784265 → 80.0.0-SNAPSHOT.1768517142984

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.
@@ -83,7 +83,7 @@ export declare class GridLocalModel extends HoistModel {
83
83
  get useScrollOptimization(): boolean;
84
84
  applyScrollOptimization(): void;
85
85
  columnsReaction(): {
86
- track: () => ((import("@xh/hoist/cmp/grid").Column | import("@xh/hoist/cmp/grid").ColumnGroup)[] | GridApi<any>)[];
86
+ track: () => (import("@xh/hoist/cmp/grid").ColumnOrGroup[] | GridApi<any>)[];
87
87
  run: ([api]: [any]) => void;
88
88
  };
89
89
  columnStateReaction(): ReactionSpec<[GridApi, ColumnState[]]>;
@@ -1,5 +1,5 @@
1
1
  import { AgGridModel } from '@xh/hoist/cmp/ag-grid';
2
- import { Column, ColumnGroup, ColumnGroupSpec, ColumnSpec, GridAutosizeMode, GridFilterModelConfig, GridGroupSortFn, TreeStyle } from '@xh/hoist/cmp/grid';
2
+ import { Column, ColumnGroup, ColumnOrGroup, ColumnOrGroupSpec, ColumnSpec, GridAutosizeMode, GridFilterModelConfig, GridGroupSortFn, TreeStyle } from '@xh/hoist/cmp/grid';
3
3
  import { GridFilterModel } from '@xh/hoist/cmp/grid/filter/GridFilterModel';
4
4
  import { Awaitable, HoistModel, HSide, PlainObject, SizingMode, Some, TaskObserver, Thunkable, VSide } from '@xh/hoist/core';
5
5
  import { Store, StoreConfig, StoreRecord, StoreRecordId, StoreRecordOrId, StoreSelectionConfig, StoreSelectionModel, StoreTransaction } from '@xh/hoist/data';
@@ -12,7 +12,7 @@ import { GridSorter, GridSorterLike } from './GridSorter';
12
12
  import { ColChooserConfig, ColumnState, GridModelPersistOptions, GroupRowRenderer, RowClassFn, RowClassRuleFn } from './Types';
13
13
  export interface GridConfig {
14
14
  /** Columns for this grid. */
15
- columns?: Array<ColumnSpec | ColumnGroupSpec>;
15
+ columns?: ColumnOrGroupSpec[];
16
16
  /** Column configs to be set on all columns. Merges deeply. */
17
17
  colDefaults?: Partial<ColumnSpec>;
18
18
  /**
@@ -280,7 +280,7 @@ export declare class GridModel extends HoistModel {
280
280
  filterModel: GridFilterModel;
281
281
  agGridModel: AgGridModel;
282
282
  viewRef: RefObject<HTMLDivElement>;
283
- columns: Array<ColumnGroup | Column>;
283
+ columns: ColumnOrGroup[];
284
284
  columnState: ColumnState[];
285
285
  expandState: any;
286
286
  sortBy: GridSorter[];
@@ -478,7 +478,7 @@ export declare class GridModel extends HoistModel {
478
478
  updateData(rawData: PlainObject[] | StoreTransaction): import("@xh/hoist/data").StoreChangeLog;
479
479
  /** Clear the underlying store, removing all rows. */
480
480
  clear(): void;
481
- setColumns(colConfigs: Array<ColumnSpec | ColumnGroupSpec>): void;
481
+ setColumns(colConfigs: ColumnOrGroupSpec[]): void;
482
482
  setColumnState(colState: ColumnState[]): void;
483
483
  showColChooser(): void;
484
484
  noteAgColumnStateChanged(agColState: AgColumnState[]): void;
@@ -530,9 +530,9 @@ export declare class GridModel extends HoistModel {
530
530
  */
531
531
  getColumnPinned(colId: string): HSide;
532
532
  /** Return matching leaf-level Column object from the provided collection. */
533
- findColumn(cols: Array<Column | ColumnGroup>, colId: string): Column;
533
+ findColumn(cols: ColumnOrGroup[], colId: string): Column;
534
534
  /** Return matching ColumnGroup from the provided collection. */
535
- findColumnGroup(cols: Array<Column | ColumnGroup>, groupId: string): ColumnGroup;
535
+ findColumnGroup(cols: ColumnOrGroup[], groupId: string): ColumnGroup;
536
536
  /**
537
537
  * Return the current state object representation for the given colId.
538
538
  *
@@ -1,11 +1,11 @@
1
1
  import { GridFilterFieldSpecConfig } from '@xh/hoist/cmp/grid/filter/GridFilterFieldSpec';
2
2
  import { HSide, PersistOptions, Some } from '@xh/hoist/core';
3
- import { Store, StoreRecord, View } from '@xh/hoist/data';
4
- import { ReactElement, ReactNode } from 'react';
5
- import { Column } from './columns/Column';
6
- import { ColumnGroup } from './columns/ColumnGroup';
7
- import { GridModel } from './GridModel';
8
- import type { CellClassParams, HeaderClassParams, HeaderValueGetterParams, ICellRendererParams, IRowNode, ITooltipParams, RowClassParams, ValueSetterParams, CustomCellEditorProps } from '@xh/hoist/kit/ag-grid';
3
+ import { FilterBindTarget, FilterValueSource, Store, StoreRecord } from '@xh/hoist/data';
4
+ import type { CellClassParams, CustomCellEditorProps, HeaderClassParams, HeaderValueGetterParams, ICellRendererParams, IRowNode, ITooltipParams, RowClassParams, ValueSetterParams } from '@xh/hoist/kit/ag-grid';
5
+ import type { ReactElement, ReactNode } from 'react';
6
+ import type { Column, ColumnSpec } from './columns/Column';
7
+ import type { ColumnGroup, ColumnGroupSpec } from './columns/ColumnGroup';
8
+ import type { GridModel } from './GridModel';
9
9
  export interface ColumnState {
10
10
  colId: string;
11
11
  width: number;
@@ -57,10 +57,11 @@ export interface GridModelPersistOptions extends PersistOptions {
57
57
  }
58
58
  export interface GridFilterModelConfig {
59
59
  /**
60
- * Store / Cube View to be filtered as column filters are applied. Defaulted to the
61
- * gridModel's store.
60
+ * Target (typically a {@link Store} or Cube {@link View}) to be filtered as column filters
61
+ * are applied and used as a source for unique values displayed in the filtering UI when
62
+ * applicable. Defaulted to the gridModel's store.
62
63
  */
63
- bind?: Store | View;
64
+ bind?: GridFilterBindTarget;
64
65
  /**
65
66
  * True to update filters immediately after each change made in the column-based filter UI.
66
67
  * Defaults to False.
@@ -68,13 +69,14 @@ export interface GridFilterModelConfig {
68
69
  commitOnChange?: boolean;
69
70
  /**
70
71
  * Specifies the fields this model supports for filtering. Should be configs for
71
- * {@link GridFilterFieldSpec}, string names to match with Fields in bound Store/View, or omitted
72
- * entirely to indicate that all fields should be filter-enabled.
72
+ * {@link GridFilterFieldSpec}, string names to match with Fields in bound Store/View, or
73
+ * omitted entirely to indicate that all fields should be filter-enabled.
73
74
  */
74
75
  fieldSpecs?: Array<string | GridFilterFieldSpecConfig>;
75
76
  /** Default properties to be assigned to all fieldSpecs created by this model. */
76
77
  fieldSpecDefaults?: Omit<GridFilterFieldSpecConfig, 'field'>;
77
78
  }
79
+ export type GridFilterBindTarget = FilterBindTarget & FilterValueSource;
78
80
  /**
79
81
  * Renderer for a group row
80
82
  * @param context - The group renderer params from ag-Grid
@@ -102,6 +104,9 @@ export interface ColChooserConfig {
102
104
  /** Chooser height for popover and dialog. Desktop only. */
103
105
  height?: string | number;
104
106
  }
107
+ export type ColumnOrGroup = Column | ColumnGroup;
108
+ export type ColumnOrGroupSpec = ColumnSpec | ColumnGroupSpec;
109
+ export declare function isColumnSpec(spec: ColumnOrGroupSpec): spec is ColumnSpec;
105
110
  /**
106
111
  * Sort comparator function for a grid column. Note that this comparator will also be called if
107
112
  * agGrid-provided column filtering is enabled: it is used to sort values shown for set filter
@@ -191,7 +196,7 @@ export type ColumnTooltipFn<T = any> = (value: T, cellContext: CellContext & {
191
196
  * @returns CSS class(es) to use.
192
197
  */
193
198
  export type ColumnHeaderClassFn = (context: {
194
- column: Column | ColumnGroup;
199
+ column: ColumnOrGroup;
195
200
  gridModel: GridModel;
196
201
  agParams: HeaderClassParams;
197
202
  }) => Some<string>;
@@ -2,7 +2,7 @@ import { HAlign, PlainObject, Some, Thunkable } from '@xh/hoist/core';
2
2
  import type { ColGroupDef } from '@xh/hoist/kit/ag-grid';
3
3
  import { ReactNode } from 'react';
4
4
  import { GridModel } from '../GridModel';
5
- import { ColumnHeaderClassFn, ColumnHeaderNameFn } from '../Types';
5
+ import { ColumnHeaderClassFn, ColumnHeaderNameFn, ColumnOrGroup } from '../Types';
6
6
  import { Column, ColumnSpec } from './Column';
7
7
  export interface ColumnGroupSpec {
8
8
  /** Column or ColumnGroup configs for children of this group.*/
@@ -35,7 +35,7 @@ export interface ColumnGroupSpec {
35
35
  * Provided to GridModels as plain configuration objects.
36
36
  */
37
37
  export declare class ColumnGroup {
38
- readonly children: Array<ColumnGroup | Column>;
38
+ readonly children: ColumnOrGroup[];
39
39
  readonly gridModel: GridModel;
40
40
  readonly groupId: string;
41
41
  readonly headerName: ReactNode | ColumnHeaderNameFn;
@@ -60,7 +60,7 @@ export declare class ColumnGroup {
60
60
  *
61
61
  * @internal
62
62
  */
63
- constructor(config: ColumnGroupSpec, gridModel: GridModel, children: Array<Column | ColumnGroup>);
63
+ constructor(config: ColumnGroupSpec, gridModel: GridModel, children: ColumnOrGroup[]);
64
64
  getAgSpec(): ColGroupDef;
65
65
  getLeafColumns(): Column[];
66
66
  }
@@ -1,6 +1,6 @@
1
- import { GridFilterFieldSpec, GridFilterModelConfig } from '@xh/hoist/cmp/grid';
1
+ import { GridFilterBindTarget, GridFilterFieldSpec, GridFilterModelConfig } from '@xh/hoist/cmp/grid';
2
2
  import { HoistModel } from '@xh/hoist/core';
3
- import { CompoundFilter, FieldFilter, Filter, FilterLike, Store, View } from '@xh/hoist/data';
3
+ import { CompoundFilter, FieldFilter, Filter, FilterLike } from '@xh/hoist/data';
4
4
  import { GridModel } from '../GridModel';
5
5
  /**
6
6
  * Model for managing a Grid's column filters.
@@ -9,7 +9,7 @@ import { GridModel } from '../GridModel';
9
9
  export declare class GridFilterModel extends HoistModel {
10
10
  xhImpl: boolean;
11
11
  gridModel: GridModel;
12
- bind: Store | View;
12
+ bind: GridFilterBindTarget;
13
13
  commitOnChange: boolean;
14
14
  fieldSpecs: GridFilterFieldSpec[];
15
15
  get filter(): Filter;
@@ -1,5 +1,5 @@
1
- import { Column, ColumnGroup, ColumnRenderer, GroupRowRenderer } from '@xh/hoist/cmp/grid';
2
- import { HeaderClassParams } from '@xh/hoist/kit/ag-grid';
1
+ import { ColumnOrGroup, ColumnRenderer, GroupRowRenderer } from '@xh/hoist/cmp/grid';
2
+ import type { HeaderClassParams } from '@xh/hoist/kit/ag-grid';
3
3
  /** @internal */
4
4
  export declare function managedRenderer<T extends ColumnRenderer | GroupRowRenderer>(fn: T, identifier: string): T;
5
5
  /**
@@ -8,4 +8,4 @@ export declare function managedRenderer<T extends ColumnRenderer | GroupRowRende
8
8
  *
9
9
  * @internal
10
10
  */
11
- export declare function getAgHeaderClassFn(column: Column | ColumnGroup): (params: HeaderClassParams) => string[];
11
+ export declare function getAgHeaderClassFn(column: ColumnOrGroup): (params: HeaderClassParams) => string[];
@@ -75,7 +75,7 @@ export declare class TabContainerModel extends HoistModel {
75
75
  protected lastActiveTabId: string;
76
76
  /**
77
77
  * @param config - TabContainer configuration.
78
- * @param [depth] - Depth in hierarchy of nested TabContainerModels. Not for application use.
78
+ * @param depth - Depth in hierarchy of nested TabContainerModels. Not for application use.
79
79
  */
80
80
  constructor({ tabs, defaultTabId, route, track, renderMode, refreshMode, persistWith, emptyText, xhImpl, switcher }: TabContainerConfig, depth?: number);
81
81
  /** Set/replace all tabs within the container. */
@@ -1,14 +1,14 @@
1
1
  import { HoistBase, PlainObject, Some } from '@xh/hoist/core';
2
- import { CubeField, CubeFieldSpec } from './CubeField';
3
- import { ViewRowData } from './ViewRowData';
4
- import { QueryConfig } from './Query';
5
- import { View } from './View';
6
2
  import { Store, StoreRecordIdSpec, StoreTransaction } from '../Store';
7
3
  import { StoreRecord } from '../StoreRecord';
4
+ import { BucketSpec } from './BucketSpec';
5
+ import { CubeField, CubeFieldSpec } from './CubeField';
6
+ import { QueryConfig } from './Query';
8
7
  import { AggregateRow } from './row/AggregateRow';
9
- import { BucketRow } from './row/BucketRow';
10
8
  import { BaseRow } from './row/BaseRow';
11
- import { BucketSpec } from './BucketSpec';
9
+ import { BucketRow } from './row/BucketRow';
10
+ import { View } from './View';
11
+ import { ViewRowData } from './ViewRowData';
12
12
  export interface CubeConfig {
13
13
  fields: CubeField[] | CubeFieldSpec[];
14
14
  /** Default configs applied to all `CubeField`s constructed internally by this Cube. */
@@ -91,6 +91,7 @@ export declare class Cube extends HoistBase {
91
91
  get empty(): boolean;
92
92
  /** Count of currently connected, auto-updating Views. */
93
93
  get connectedViewCount(): number;
94
+ getField(name: string): CubeField;
94
95
  /**
95
96
  * Query the cube.
96
97
  *
@@ -10,10 +10,13 @@ import {
10
10
  ColumnCellClassRuleFn,
11
11
  ColumnGroup,
12
12
  ColumnGroupSpec,
13
+ ColumnOrGroup,
14
+ ColumnOrGroupSpec,
13
15
  ColumnSpec,
14
16
  GridAutosizeMode,
15
17
  GridFilterModelConfig,
16
18
  GridGroupSortFn,
19
+ isColumnSpec,
17
20
  TreeStyle
18
21
  } from '@xh/hoist/cmp/grid';
19
22
  import {GridFilterModel} from '@xh/hoist/cmp/grid/filter/GridFilterModel';
@@ -32,6 +35,7 @@ import {
32
35
  XH
33
36
  } from '@xh/hoist/core';
34
37
  import {
38
+ Field,
35
39
  FieldSpec,
36
40
  Store,
37
41
  StoreConfig,
@@ -117,7 +121,7 @@ import {
117
121
 
118
122
  export interface GridConfig {
119
123
  /** Columns for this grid. */
120
- columns?: Array<ColumnSpec | ColumnGroupSpec>;
124
+ columns?: ColumnOrGroupSpec[];
121
125
 
122
126
  /** Column configs to be set on all columns. Merges deeply. */
123
127
  colDefaults?: Partial<ColumnSpec>;
@@ -454,7 +458,7 @@ export class GridModel extends HoistModel {
454
458
  //------------------------
455
459
  // Observable API
456
460
  //------------------------
457
- @observable.ref columns: Array<ColumnGroup | Column> = [];
461
+ @observable.ref columns: ColumnOrGroup[] = [];
458
462
  @observable.ref columnState: ColumnState[] = [];
459
463
  @observable.ref expandState: any = {};
460
464
  @observable.ref sortBy: GridSorter[] = [];
@@ -1167,7 +1171,7 @@ export class GridModel extends HoistModel {
1167
1171
  }
1168
1172
 
1169
1173
  @action
1170
- setColumns(colConfigs: Array<ColumnSpec | ColumnGroupSpec>) {
1174
+ setColumns(colConfigs: ColumnOrGroupSpec[]) {
1171
1175
  this.validateColConfigs(colConfigs);
1172
1176
  colConfigs = this.enhanceColConfigsFromStore(colConfigs);
1173
1177
 
@@ -1362,7 +1366,7 @@ export class GridModel extends HoistModel {
1362
1366
  }
1363
1367
 
1364
1368
  /** Return matching leaf-level Column object from the provided collection. */
1365
- findColumn(cols: Array<Column | ColumnGroup>, colId: string): Column {
1369
+ findColumn(cols: ColumnOrGroup[], colId: string): Column {
1366
1370
  for (let col of cols) {
1367
1371
  if (col instanceof ColumnGroup) {
1368
1372
  const ret = this.findColumn(col.children, colId);
@@ -1375,7 +1379,7 @@ export class GridModel extends HoistModel {
1375
1379
  }
1376
1380
 
1377
1381
  /** Return matching ColumnGroup from the provided collection. */
1378
- findColumnGroup(cols: Array<Column | ColumnGroup>, groupId: string): ColumnGroup {
1382
+ findColumnGroup(cols: ColumnOrGroup[], groupId: string): ColumnGroup {
1379
1383
  for (let col of cols) {
1380
1384
  if (col instanceof ColumnGroup) {
1381
1385
  if (col.groupId === groupId) return col;
@@ -1595,7 +1599,7 @@ export class GridModel extends HoistModel {
1595
1599
  //-----------------------
1596
1600
  // Implementation
1597
1601
  //-----------------------
1598
- private buildColumn(config: ColumnGroupSpec | ColumnSpec, borderedGroup?: ColumnGroupSpec) {
1602
+ private buildColumn(config: ColumnOrGroupSpec, borderedGroup?: ColumnGroupSpec): ColumnOrGroup {
1599
1603
  // Merge leaf config with defaults.
1600
1604
  // Ensure *any* tooltip setting on column itself always wins.
1601
1605
  if (this.colDefaults && !this.isGroupSpec(config)) {
@@ -1609,9 +1613,7 @@ export class GridModel extends HoistModel {
1609
1613
 
1610
1614
  if (this.isGroupSpec(config)) {
1611
1615
  if (config.borders !== false) borderedGroup = config;
1612
- const children = compact(
1613
- config.children.map(c => this.buildColumn(c, borderedGroup))
1614
- ) as Array<ColumnGroup | Column>;
1616
+ const children = compact(config.children.map(c => this.buildColumn(c, borderedGroup)));
1615
1617
  return !isEmpty(children)
1616
1618
  ? new ColumnGroup(config as ColumnGroupSpec, this, children)
1617
1619
  : null;
@@ -1649,19 +1651,23 @@ export class GridModel extends HoistModel {
1649
1651
  }
1650
1652
  }
1651
1653
 
1652
- private gatherLeaves(columns, leaves = []) {
1654
+ private gatherLeaves(columns: ColumnOrGroup[], leaves: Column[] = []): Column[] {
1653
1655
  columns.forEach(col => {
1654
- if (col.groupId) this.gatherLeaves(col.children, leaves);
1655
- if (col.colId) leaves.push(col);
1656
+ if (col instanceof ColumnGroup) {
1657
+ this.gatherLeaves(col.children, leaves);
1658
+ } else {
1659
+ leaves.push(col);
1660
+ }
1656
1661
  });
1657
1662
 
1658
1663
  return leaves;
1659
1664
  }
1660
1665
 
1661
- private collectIds(cols, ids = []) {
1666
+ private collectIds(cols: ColumnOrGroup[], ids: string[] = []) {
1662
1667
  cols.forEach(col => {
1663
- if (col.colId) ids.push(col.colId);
1664
- if (col.groupId) {
1668
+ if (col instanceof Column) {
1669
+ ids.push(col.colId);
1670
+ } else {
1665
1671
  ids.push(col.groupId);
1666
1672
  this.collectIds(col.children, ids);
1667
1673
  }
@@ -1686,7 +1692,10 @@ export class GridModel extends HoistModel {
1686
1692
  // so it can be better re-used across Hoist APIs such as `Filter` and `FormModel`. However for
1687
1693
  // convenience, a `GridModel.store` config can also be very minimal (or non-existent), and
1688
1694
  // in this case GridModel should work out the required Store fields from column definitions.
1689
- private parseAndSetColumnsAndStore(colConfigs, store = {}) {
1695
+ private parseAndSetColumnsAndStore(
1696
+ colConfigs: ColumnOrGroupSpec[],
1697
+ store: Store | StoreConfig = {}
1698
+ ) {
1690
1699
  // 1) Validate configs.
1691
1700
  this.validateStoreConfig(store);
1692
1701
  this.validateColConfigs(colConfigs);
@@ -1711,14 +1720,14 @@ export class GridModel extends HoistModel {
1711
1720
  this.store = newStore;
1712
1721
  }
1713
1722
 
1714
- private validateStoreConfig(store) {
1723
+ private validateStoreConfig(store: Store | StoreConfig) {
1715
1724
  throwIf(
1716
1725
  !(store instanceof Store || isPlainObject(store)),
1717
1726
  'GridModel.store config must be either an instance of a Store or a config to create one.'
1718
1727
  );
1719
1728
  }
1720
1729
 
1721
- private validateColConfigs(colConfigs) {
1730
+ private validateColConfigs(colConfigs: ColumnOrGroupSpec[]) {
1722
1731
  throwIf(!isArray(colConfigs), 'GridModel.columns config must be an array.');
1723
1732
  throwIf(
1724
1733
  colConfigs.some(c => !isPlainObject(c)),
@@ -1726,7 +1735,7 @@ export class GridModel extends HoistModel {
1726
1735
  );
1727
1736
  }
1728
1737
 
1729
- private validateColumns(cols) {
1738
+ private validateColumns(cols: ColumnOrGroup[]) {
1730
1739
  if (isEmpty(cols)) return;
1731
1740
 
1732
1741
  const ids = this.collectIds(cols);
@@ -1782,16 +1791,30 @@ export class GridModel extends HoistModel {
1782
1791
 
1783
1792
  // Selectively enhance raw column configs with field-level metadata from store.fields and/or
1784
1793
  // field config partials provided by the column configs themselves.
1785
- private enhanceColConfigsFromStore(colConfigs, storeOrConfig?) {
1794
+ private enhanceColConfigsFromStore(
1795
+ colConfigs: ColumnOrGroupSpec[],
1796
+ storeOrConfig?: Store | StoreConfig
1797
+ ): ColumnOrGroupSpec[] {
1786
1798
  const store = storeOrConfig || this.store,
1787
1799
  storeFields = store?.fields,
1788
- fieldsByName = {};
1800
+ fieldsByName: Record<string, Field | FieldSpec> = {};
1789
1801
 
1790
1802
  // Extract field definitions in all supported forms: pull Field instances/configs from
1791
- // storeFields first, then fill in with any col-level `field` config objects.
1792
- storeFields?.forEach(sf => (fieldsByName[sf.name] = sf));
1803
+ // storeFields first...
1804
+ storeFields?.forEach(sf => {
1805
+ if (sf && !isString(sf)) {
1806
+ fieldsByName[sf.name] = sf;
1807
+ }
1808
+ });
1809
+
1810
+ // Then fill in with any col-level `field` config objects.
1793
1811
  colConfigs.forEach(cc => {
1794
- if (isPlainObject(cc.field) && !fieldsByName[cc.field.name]) {
1812
+ if (
1813
+ isColumnSpec(cc) &&
1814
+ cc.field &&
1815
+ !isString(cc.field) &&
1816
+ !fieldsByName[cc.field.name]
1817
+ ) {
1795
1818
  fieldsByName[cc.field.name] = cc.field;
1796
1819
  }
1797
1820
  });
@@ -1800,16 +1823,17 @@ export class GridModel extends HoistModel {
1800
1823
 
1801
1824
  const numTypes = ['int', 'number'],
1802
1825
  dateTypes = ['date', 'localDate'];
1826
+
1803
1827
  return colConfigs.map(col => {
1804
1828
  // Recurse into children for column groups
1805
- if (col.children) {
1829
+ if (!isColumnSpec(col)) {
1806
1830
  return {
1807
1831
  ...col,
1808
1832
  children: this.enhanceColConfigsFromStore(col.children, storeOrConfig)
1809
1833
  };
1810
1834
  }
1811
1835
 
1812
- const colFieldName = isPlainObject(col.field) ? col.field.name : col.field,
1836
+ const colFieldName = isString(col.field) ? col.field : col.field?.name,
1813
1837
  field = fieldsByName[colFieldName];
1814
1838
 
1815
1839
  if (!field) return col;
@@ -1837,9 +1861,9 @@ export class GridModel extends HoistModel {
1837
1861
  // Ensure store config has a complete set of fields for all configured columns. Note this
1838
1862
  // requires columns to have been constructed and set, and will only work with a raw store
1839
1863
  // config object, not an instance.
1840
- private enhanceStoreConfigFromColumns(storeConfig) {
1864
+ private enhanceStoreConfigFromColumns(storeConfig: StoreConfig) {
1841
1865
  const fields = storeConfig.fields ?? [],
1842
- storeFieldNames = fields.map(it => it.name ?? it),
1866
+ storeFieldNames = fields.map(it => (isString(it) ? it : it.name)),
1843
1867
  leafColsByFieldName = this.leafColsByFieldName();
1844
1868
 
1845
1869
  const newFields: FieldSpec[] = [];
@@ -1886,31 +1910,33 @@ export class GridModel extends HoistModel {
1886
1910
  return sizingMode;
1887
1911
  }
1888
1912
 
1889
- private parseSelModel(selModel): StoreSelectionModel {
1890
- const {store} = this;
1891
- selModel = withDefault(selModel, XH.isMobileApp ? 'disabled' : 'single');
1892
-
1913
+ private parseSelModel(selModel: GridConfig['selModel']): StoreSelectionModel {
1914
+ // Return actual instance directly.
1893
1915
  if (selModel instanceof StoreSelectionModel) {
1894
1916
  return selModel;
1895
1917
  }
1896
1918
 
1897
- if (isPlainObject(selModel)) {
1898
- return this.markManaged(new StoreSelectionModel({...selModel, store, xhImpl: true}));
1919
+ // Default unspecified based on platform, treat explicit null as disabled.
1920
+ if (selModel === undefined) {
1921
+ selModel = XH.isMobileApp ? 'disabled' : 'single';
1922
+ } else if (selModel === null) {
1923
+ selModel = 'disabled';
1899
1924
  }
1900
1925
 
1901
- // Assume its just the mode...
1902
- let mode: any = 'single';
1926
+ // Strings specify the mode.
1903
1927
  if (isString(selModel)) {
1904
- mode = selModel;
1905
- } else if (selModel === null) {
1906
- mode = 'disabled';
1928
+ selModel = {mode: selModel};
1907
1929
  }
1908
- return this.markManaged(new StoreSelectionModel({mode, store, xhImpl: true}));
1930
+
1931
+ return this.markManaged(
1932
+ new StoreSelectionModel({...selModel, store: this.store, xhImpl: true})
1933
+ );
1909
1934
  }
1910
1935
 
1911
- private parseFilterModel(filterModel) {
1936
+ private parseFilterModel(filterModel: GridConfig['filterModel']) {
1912
1937
  if (XH.isMobileApp || !filterModel) return null;
1913
- filterModel = isPlainObject(filterModel) ? filterModel : {};
1938
+
1939
+ filterModel = filterModel === true ? {} : filterModel;
1914
1940
  return new GridFilterModel({bind: this.store, ...filterModel}, this);
1915
1941
  }
1916
1942
 
@@ -1921,17 +1947,15 @@ export class GridModel extends HoistModel {
1921
1947
  };
1922
1948
  }
1923
1949
 
1924
- private parseChooserModel(chooserModel): HoistModel {
1925
- const modelClass = XH.isMobileApp ? MobileColChooserModel : DesktopColChooserModel;
1926
-
1927
- if (isPlainObject(chooserModel)) {
1928
- return this.markManaged(new modelClass({...chooserModel, gridModel: this}));
1929
- }
1950
+ private parseChooserModel(chooserModel: GridConfig['colChooserModel']): HoistModel {
1951
+ if (!chooserModel) return null;
1930
1952
 
1931
- return chooserModel ? this.markManaged(new modelClass({gridModel: this})) : null;
1953
+ const modelClass = XH.isMobileApp ? MobileColChooserModel : DesktopColChooserModel;
1954
+ chooserModel = chooserModel === true ? {} : chooserModel;
1955
+ return this.markManaged(new modelClass({...chooserModel, gridModel: this}));
1932
1956
  }
1933
1957
 
1934
- private isGroupSpec(col: ColumnGroupSpec | ColumnSpec): col is ColumnGroupSpec {
1958
+ private isGroupSpec(col: ColumnOrGroupSpec): col is ColumnGroupSpec {
1935
1959
  return 'children' in col;
1936
1960
  }
1937
1961
 
package/cmp/grid/Types.ts CHANGED
@@ -7,23 +7,23 @@
7
7
 
8
8
  import {GridFilterFieldSpecConfig} from '@xh/hoist/cmp/grid/filter/GridFilterFieldSpec';
9
9
  import {HSide, PersistOptions, Some} from '@xh/hoist/core';
10
- import {Store, StoreRecord, View} from '@xh/hoist/data';
11
- import {ReactElement, ReactNode} from 'react';
12
- import {Column} from './columns/Column';
13
- import {ColumnGroup} from './columns/ColumnGroup';
14
- import {GridModel} from './GridModel';
10
+ import {FilterBindTarget, FilterValueSource, Store, StoreRecord} from '@xh/hoist/data';
15
11
 
16
12
  import type {
17
13
  CellClassParams,
14
+ CustomCellEditorProps,
18
15
  HeaderClassParams,
19
16
  HeaderValueGetterParams,
20
17
  ICellRendererParams,
21
18
  IRowNode,
22
19
  ITooltipParams,
23
20
  RowClassParams,
24
- ValueSetterParams,
25
- CustomCellEditorProps
21
+ ValueSetterParams
26
22
  } from '@xh/hoist/kit/ag-grid';
23
+ import type {ReactElement, ReactNode} from 'react';
24
+ import type {Column, ColumnSpec} from './columns/Column';
25
+ import type {ColumnGroup, ColumnGroupSpec} from './columns/ColumnGroup';
26
+ import type {GridModel} from './GridModel';
27
27
 
28
28
  export interface ColumnState {
29
29
  colId: string;
@@ -87,10 +87,11 @@ export interface GridModelPersistOptions extends PersistOptions {
87
87
 
88
88
  export interface GridFilterModelConfig {
89
89
  /**
90
- * Store / Cube View to be filtered as column filters are applied. Defaulted to the
91
- * gridModel's store.
90
+ * Target (typically a {@link Store} or Cube {@link View}) to be filtered as column filters
91
+ * are applied and used as a source for unique values displayed in the filtering UI when
92
+ * applicable. Defaulted to the gridModel's store.
92
93
  */
93
- bind?: Store | View;
94
+ bind?: GridFilterBindTarget;
94
95
 
95
96
  /**
96
97
  * True to update filters immediately after each change made in the column-based filter UI.
@@ -100,8 +101,8 @@ export interface GridFilterModelConfig {
100
101
 
101
102
  /**
102
103
  * Specifies the fields this model supports for filtering. Should be configs for
103
- * {@link GridFilterFieldSpec}, string names to match with Fields in bound Store/View, or omitted
104
- * entirely to indicate that all fields should be filter-enabled.
104
+ * {@link GridFilterFieldSpec}, string names to match with Fields in bound Store/View, or
105
+ * omitted entirely to indicate that all fields should be filter-enabled.
105
106
  */
106
107
  fieldSpecs?: Array<string | GridFilterFieldSpecConfig>;
107
108
 
@@ -109,6 +110,8 @@ export interface GridFilterModelConfig {
109
110
  fieldSpecDefaults?: Omit<GridFilterFieldSpecConfig, 'field'>;
110
111
  }
111
112
 
113
+ export type GridFilterBindTarget = FilterBindTarget & FilterValueSource;
114
+
112
115
  /**
113
116
  * Renderer for a group row
114
117
  * @param context - The group renderer params from ag-Grid
@@ -142,6 +145,13 @@ export interface ColChooserConfig {
142
145
  height?: string | number;
143
146
  }
144
147
 
148
+ export type ColumnOrGroup = Column | ColumnGroup;
149
+ export type ColumnOrGroupSpec = ColumnSpec | ColumnGroupSpec;
150
+
151
+ export function isColumnSpec(spec: ColumnOrGroupSpec): spec is ColumnSpec {
152
+ return !(spec as ColumnGroupSpec).children;
153
+ }
154
+
145
155
  /**
146
156
  * Sort comparator function for a grid column. Note that this comparator will also be called if
147
157
  * agGrid-provided column filtering is enabled: it is used to sort values shown for set filter
@@ -248,7 +258,7 @@ export type ColumnTooltipFn<T = any> = (
248
258
  * @returns CSS class(es) to use.
249
259
  */
250
260
  export type ColumnHeaderClassFn = (context: {
251
- column: Column | ColumnGroup;
261
+ column: ColumnOrGroup;
252
262
  gridModel: GridModel;
253
263
  agParams: HeaderClassParams;
254
264
  }) => Some<string>;
@@ -13,7 +13,7 @@ import {throwIf, withDefault} from '@xh/hoist/utils/js';
13
13
  import {clone, isEmpty, isFunction, isString, keysIn} from 'lodash';
14
14
  import {ReactNode} from 'react';
15
15
  import {GridModel} from '../GridModel';
16
- import {ColumnHeaderClassFn, ColumnHeaderNameFn} from '../Types';
16
+ import {ColumnHeaderClassFn, ColumnHeaderNameFn, ColumnOrGroup} from '../Types';
17
17
  import {Column, ColumnSpec} from './Column';
18
18
 
19
19
  export interface ColumnGroupSpec {
@@ -51,7 +51,7 @@ export interface ColumnGroupSpec {
51
51
  * Provided to GridModels as plain configuration objects.
52
52
  */
53
53
  export class ColumnGroup {
54
- readonly children: Array<ColumnGroup | Column>;
54
+ readonly children: ColumnOrGroup[];
55
55
  readonly gridModel: GridModel;
56
56
  readonly groupId: string;
57
57
  readonly headerName: ReactNode | ColumnHeaderNameFn;
@@ -79,11 +79,7 @@ export class ColumnGroup {
79
79
  *
80
80
  * @internal
81
81
  */
82
- constructor(
83
- config: ColumnGroupSpec,
84
- gridModel: GridModel,
85
- children: Array<Column | ColumnGroup>
86
- ) {
82
+ constructor(config: ColumnGroupSpec, gridModel: GridModel, children: ColumnOrGroup[]) {
87
83
  const {
88
84
  children: childrenSpecs,
89
85
  groupId,