@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.
- package/CHANGELOG.md +8 -0
- package/build/types/cmp/grid/GridModel.d.ts +1 -1
- package/build/types/cmp/grid/Types.d.ts +7 -3
- package/build/types/cmp/store/StoreFilterField.d.ts +3 -3
- package/build/types/cmp/store/impl/StoreFilterFieldImplModel.d.ts +9 -7
- package/build/types/data/filter/Types.d.ts +7 -0
- package/build/types/desktop/cmp/grid/find/GridFindField.d.ts +3 -2
- package/build/types/desktop/cmp/grid/find/impl/GridFindFieldImplModel.d.ts +5 -3
- package/build/types/desktop/cmp/grid/impl/colchooser/ColChooserModel.d.ts +6 -11
- package/build/types/desktop/cmp/leftrightchooser/LeftRightChooserFilter.d.ts +3 -2
- package/cmp/grid/GridModel.ts +1 -1
- package/cmp/grid/Types.ts +15 -4
- package/cmp/store/StoreFilterField.ts +3 -3
- package/cmp/store/impl/StoreFilterFieldImplModel.ts +32 -26
- package/data/Store.ts +4 -2
- package/data/filter/Types.ts +8 -0
- package/desktop/cmp/grid/find/GridFindField.ts +3 -2
- package/desktop/cmp/grid/find/impl/GridFindFieldImplModel.ts +41 -37
- package/desktop/cmp/grid/impl/colchooser/ColChooser.ts +2 -2
- package/desktop/cmp/grid/impl/colchooser/ColChooserModel.ts +9 -5
- package/desktop/cmp/leftrightchooser/LeftRightChooserFilter.ts +26 -11
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -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():
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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.
|
|
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
|
-
/**
|
|
20
|
-
|
|
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']
|
|
65
|
-
|
|
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 &&
|
|
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.
|
|
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",
|