@xh/hoist 80.0.0-SNAPSHOT.1768931272469 → 80.0.0-SNAPSHOT.1769011463076

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.
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import {GridModel} from '@xh/hoist/cmp/grid';
8
8
  import {HoistModel, XH} from '@xh/hoist/core';
9
+ import type {FilterMatchMode, StoreRecord} from '@xh/hoist/data';
9
10
  import {TextInputModel} from '@xh/hoist/desktop/cmp/input';
10
11
  import {action, bindable, comparer, computed, makeObservable, observable} from '@xh/hoist/mobx';
11
12
  import {stripTags, withDefault} from '@xh/hoist/utils/js';
@@ -32,22 +33,25 @@ export class GridFindFieldImplModel extends HoistModel {
32
33
  @bindable
33
34
  query: string = null;
34
35
 
35
- get matchMode(): string {
36
+ get matchMode(): FilterMatchMode {
36
37
  return this.componentProps.matchMode ?? 'startWord';
37
38
  }
39
+
38
40
  get queryBuffer(): number {
39
41
  return this.componentProps.queryBuffer ?? 200;
40
42
  }
43
+
41
44
  get includeFields(): string[] {
42
45
  return this.componentProps.includeFields;
43
46
  }
47
+
44
48
  get excludeFields(): string[] {
45
49
  return this.componentProps.excludeFields;
46
50
  }
47
51
 
48
52
  @observable.ref results;
49
53
  inputRef = createObservableRef<TextInputModel>();
50
- _records = null;
54
+ _records: StoreRecord[] = null;
51
55
 
52
56
  get count(): number {
53
57
  return this.results?.length;
@@ -81,7 +85,7 @@ export class GridFindFieldImplModel extends HoistModel {
81
85
  }
82
86
 
83
87
  @computed
84
- get gridModel() {
88
+ get gridModel(): GridModel {
85
89
  const ret = withDefault(this.componentProps.gridModel, this.lookupModel(GridModel));
86
90
  if (!ret) {
87
91
  this.logError("No GridModel available. Provide via a 'gridModel' prop, or context.");
@@ -100,30 +104,30 @@ export class GridFindFieldImplModel extends HoistModel {
100
104
  }
101
105
 
102
106
  override onLinked() {
103
- this.addReaction({
104
- track: () => this.query,
105
- run: () => this.updateResults(true),
106
- debounce: this.queryBuffer
107
- });
108
-
109
- this.addReaction({
110
- track: () => [
111
- this.gridModel?.store.records,
112
- this.gridModel?.columns,
113
- this.gridModel?.sortBy,
114
- this.gridModel?.groupBy
115
- ],
116
- run: () => {
117
- this._records = null;
118
- if (this.hasQuery) this.updateResults();
107
+ this.addReaction(
108
+ {
109
+ track: () => this.query,
110
+ run: () => this.updateResults(true),
111
+ debounce: this.queryBuffer
112
+ },
113
+ {
114
+ track: () => [
115
+ this.gridModel?.store.records,
116
+ this.gridModel?.columns,
117
+ this.gridModel?.sortBy,
118
+ this.gridModel?.groupBy
119
+ ],
120
+ run: () => {
121
+ this._records = null;
122
+ if (this.hasQuery) this.updateResults();
123
+ }
124
+ },
125
+ {
126
+ track: () => [this.includeFields, this.excludeFields, this.matchMode],
127
+ run: () => this.updateResults(),
128
+ equals: comparer.structural
119
129
  }
120
- });
121
-
122
- this.addReaction({
123
- track: () => [this.includeFields, this.excludeFields],
124
- run: () => this.updateResults(),
125
- equals: comparer.structural
126
- });
130
+ );
127
131
  }
128
132
 
129
133
  selectPrev() {
@@ -180,7 +184,7 @@ export class GridFindFieldImplModel extends HoistModel {
180
184
  }
181
185
  }
182
186
 
183
- private getRecords() {
187
+ private getRecords(): StoreRecord[] {
184
188
  if (!this._records) {
185
189
  const records = this.sortRecordsRecursive([...this.gridModel.store.rootRecords]);
186
190
  this._records = this.sortRecordsByGroupBy(records);
@@ -189,10 +193,10 @@ export class GridFindFieldImplModel extends HoistModel {
189
193
  }
190
194
 
191
195
  // Sort records with GridModel's sortBy(s) using the Column's comparator
192
- private sortRecordsRecursive(records) {
196
+ private sortRecordsRecursive(records: StoreRecord[]): StoreRecord[] {
193
197
  const {gridModel} = this,
194
198
  {sortBy, treeMode, agApi, store} = gridModel,
195
- ret = [];
199
+ ret: StoreRecord[] = [];
196
200
 
197
201
  [...sortBy].reverse().forEach(it => {
198
202
  const column = gridModel.getColumn(it.colId);
@@ -225,7 +229,7 @@ export class GridFindFieldImplModel extends HoistModel {
225
229
  }
226
230
 
227
231
  // Sort records with GridModel's groupBy(s) using the GridModel's groupSortFn
228
- private sortRecordsByGroupBy(records) {
232
+ private sortRecordsByGroupBy(records: StoreRecord[]) {
229
233
  const {gridModel} = this,
230
234
  {agApi, groupBy, groupSortFn, store} = gridModel;
231
235
 
@@ -249,7 +253,7 @@ export class GridFindFieldImplModel extends HoistModel {
249
253
  return records;
250
254
  }
251
255
 
252
- private getRegex(searchTerm) {
256
+ private getRegex(searchTerm: string): RegExp {
253
257
  searchTerm = escapeRegExp(searchTerm);
254
258
  switch (this.matchMode) {
255
259
  case 'any':
@@ -262,12 +266,12 @@ export class GridFindFieldImplModel extends HoistModel {
262
266
  throw XH.exception('Unknown matchMode in GridFindField');
263
267
  }
264
268
 
265
- private getActiveFields() {
269
+ private getActiveFields(): string[] {
266
270
  const {gridModel, includeFields, excludeFields} = this,
267
271
  groupBy = gridModel.groupBy,
268
272
  visibleCols = gridModel.getVisibleLeafColumns();
269
273
 
270
- let ret = ['id', ...gridModel.store.fields.map(f => f.name)];
274
+ let ret = ['id', ...gridModel.store.fieldNames];
271
275
  if (includeFields) ret = intersection(ret, includeFields);
272
276
  if (excludeFields) ret = without(ret, ...excludeFields);
273
277
 
@@ -301,7 +305,7 @@ export class GridFindFieldImplModel extends HoistModel {
301
305
  return ret;
302
306
  }
303
307
 
304
- private getValGetters(fieldName) {
308
+ private getValGetters(fieldName: string) {
305
309
  const {gridModel} = this,
306
310
  {store} = gridModel,
307
311
  field = store.getField(fieldName);
@@ -313,7 +317,7 @@ export class GridFindFieldImplModel extends HoistModel {
313
317
 
314
318
  return cols.map(column => {
315
319
  const {renderer, getValueFn} = column;
316
- return record => {
320
+ return (record: StoreRecord) => {
317
321
  const ctx = {
318
322
  record,
319
323
  field: fieldName,
@@ -332,7 +336,7 @@ export class GridFindFieldImplModel extends HoistModel {
332
336
  // Otherwise just match raw.
333
337
  // Use expensive get() only when needed to support dot-separated paths.
334
338
  return fieldName.includes('.')
335
- ? rec => get(rec.data, fieldName)
336
- : rec => rec.data[fieldName];
339
+ ? (rec: StoreRecord) => get(rec.data, fieldName)
340
+ : (rec: StoreRecord) => rec.data[fieldName];
337
341
  }
338
342
  }
@@ -32,14 +32,14 @@ export const colChooser = hoistCmp.factory<ColChooserProps>({
32
32
  className: 'xh-col-chooser',
33
33
 
34
34
  render({model, className}) {
35
- const {commitOnChange, showRestoreDefaults, width, height} = model;
35
+ const {commitOnChange, showRestoreDefaults, width, height, filterMatchMode} = model;
36
36
 
37
37
  return panel({
38
38
  className,
39
39
  items: [
40
40
  leftRightChooser({width, height}),
41
41
  toolbar(
42
- leftRightChooserFilter(),
42
+ leftRightChooserFilter({matchMode: filterMatchMode}),
43
43
  filler(),
44
44
  button({
45
45
  omit: !showRestoreDefaults,
@@ -4,8 +4,9 @@
4
4
  *
5
5
  * Copyright © 2026 Extremely Heavy Industries Inc.
6
6
  */
7
- import {GridModel} from '@xh/hoist/cmp/grid';
7
+ import {ColChooserConfig, GridModel} from '@xh/hoist/cmp/grid';
8
8
  import {HoistModel, managed} from '@xh/hoist/core';
9
+ import type {FilterMatchMode} from '@xh/hoist/data';
9
10
  import {LeftRightChooserModel} from '@xh/hoist/desktop/cmp/leftrightchooser';
10
11
  import {action, makeObservable, observable} from '@xh/hoist/mobx';
11
12
  import {sortBy} from 'lodash';
@@ -29,8 +30,9 @@ export class ColChooserModel extends HoistModel {
29
30
  commitOnChange: boolean;
30
31
  showRestoreDefaults: boolean;
31
32
  autosizeOnCommit: boolean;
32
- width: number;
33
- height: number;
33
+ width: string | number;
34
+ height: string | number;
35
+ filterMatchMode: FilterMatchMode;
34
36
 
35
37
  constructor({
36
38
  gridModel,
@@ -38,8 +40,9 @@ export class ColChooserModel extends HoistModel {
38
40
  showRestoreDefaults = true,
39
41
  autosizeOnCommit = false,
40
42
  width = !commitOnChange && showRestoreDefaults ? 600 : 520,
41
- height = 300
42
- }) {
43
+ height = 300,
44
+ filterMatchMode = 'startWord'
45
+ }: ColChooserConfig) {
43
46
  super();
44
47
  makeObservable(this);
45
48
 
@@ -49,6 +52,7 @@ export class ColChooserModel extends HoistModel {
49
52
  this.autosizeOnCommit = autosizeOnCommit;
50
53
  this.width = width;
51
54
  this.height = height;
55
+ this.filterMatchMode = filterMatchMode;
52
56
 
53
57
  this.lrModel = new LeftRightChooserModel({
54
58
  leftTitle: 'Available Columns',
@@ -4,7 +4,8 @@
4
4
  *
5
5
  * Copyright © 2026 Extremely Heavy Industries Inc.
6
6
  */
7
- import {hoistCmp, HoistModel, HoistProps, lookup, useLocalModel, uses} from '@xh/hoist/core';
7
+ import {hoistCmp, HoistModel, HoistProps, lookup, useLocalModel, uses, XH} from '@xh/hoist/core';
8
+ import type {FilterMatchMode} from '@xh/hoist/data';
8
9
  import {textInput} from '@xh/hoist/desktop/cmp/input';
9
10
  import '@xh/hoist/desktop/register';
10
11
  import {Icon} from '@xh/hoist/icon';
@@ -16,8 +17,8 @@ export interface LeftRightChooserFilterProps extends HoistProps<LeftRightChooser
16
17
  /** Names of fields in chooser on which to filter. Defaults to ['text', 'group'] */
17
18
  fields?: string[];
18
19
 
19
- /** True to prevent regex start line anchor from being added. */
20
- anyMatch?: boolean;
20
+ /** Mode to use when filtering (default 'startWord'). */
21
+ matchMode?: FilterMatchMode;
21
22
  }
22
23
 
23
24
  /**
@@ -51,34 +52,48 @@ class LeftRightChooserFilterLocalModel extends HoistModel {
51
52
  @bindable
52
53
  value = null;
53
54
 
55
+ get matchMode(): FilterMatchMode {
56
+ return this.componentProps.matchMode ?? 'startWord';
57
+ }
58
+
54
59
  constructor() {
55
60
  super();
56
61
  makeObservable(this);
57
62
  this.addReaction({
58
- track: () => this.value,
63
+ track: () => [this.value, this.matchMode],
59
64
  run: () => this.runFilter()
60
65
  });
61
66
  }
62
67
 
63
68
  private runFilter() {
64
- const {fields = ['text', 'group'], anyMatch = false} = this.componentProps;
65
- let searchTerm = escapeRegExp(this.value);
66
-
67
- if (!anyMatch) {
68
- searchTerm = `(^|\\W)${searchTerm}`;
69
- }
69
+ const {fields = ['text', 'group']} = this.componentProps,
70
+ searchTerm = this.value,
71
+ regex = this.getRegex(searchTerm);
70
72
 
71
73
  const filter = raw => {
72
74
  return fields.some(f => {
73
75
  if (!searchTerm) return true;
74
76
  const fieldVal = raw.data[f];
75
- return fieldVal && new RegExp(searchTerm, 'ig').test(fieldVal);
77
+ return fieldVal && regex.test(fieldVal);
76
78
  });
77
79
  };
78
80
 
79
81
  this.model.setDisplayFilter(filter);
80
82
  }
81
83
 
84
+ private getRegex(searchTerm: string): RegExp {
85
+ searchTerm = escapeRegExp(searchTerm);
86
+ switch (this.matchMode) {
87
+ case 'any':
88
+ return new RegExp(searchTerm, 'i');
89
+ case 'start':
90
+ return new RegExp(`^${searchTerm}`, 'i');
91
+ case 'startWord':
92
+ return new RegExp(`(^|\\W)${searchTerm}`, 'i');
93
+ }
94
+ throw XH.exception('Unknown matchMode in StoreFilterField');
95
+ }
96
+
82
97
  override destroy() {
83
98
  // This unusual bit of code is extremely important -- the model we are linking to might
84
99
  // survive the display of this component and should be restored. (This happens with GridColumnChooser)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xh/hoist",
3
- "version": "80.0.0-SNAPSHOT.1768931272469",
3
+ "version": "80.0.0-SNAPSHOT.1769011463076",
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",