@xh/hoist 73.0.0-SNAPSHOT.1746826954718 → 73.0.0-SNAPSHOT.1746830066260
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/admin/tabs/activity/tracking/ActivityTrackingPanel.ts +2 -2
- package/admin/tabs/userData/roles/RolePanel.ts +2 -2
- package/build/types/cmp/filter/FilterChooserModel.d.ts +1 -0
- package/build/types/desktop/cmp/filter/FilterChooser.d.ts +2 -0
- package/build/types/desktop/cmp/filter/PopoverFilterChooser.d.ts +10 -0
- package/build/types/desktop/cmp/filter/index.d.ts +1 -0
- package/build/types/mobx/overrides.d.ts +1 -1
- package/cmp/filter/FilterChooserModel.ts +4 -0
- package/core/HoistBaseDecorators.ts +31 -29
- package/desktop/cmp/filter/FilterChooser.scss +5 -0
- package/desktop/cmp/filter/FilterChooser.ts +60 -37
- package/desktop/cmp/filter/PopoverFilterChooser.scss +42 -0
- package/desktop/cmp/filter/PopoverFilterChooser.ts +104 -0
- package/desktop/cmp/filter/index.ts +1 -0
- package/mobx/decorators.ts +4 -32
- package/mobx/overrides.ts +19 -6
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
## v73.0.0-SNAPSHOT - unreleased
|
|
4
4
|
|
|
5
|
+
### 🎁 New Features
|
|
6
|
+
|
|
7
|
+
* Added `PopoverFilterChooser`, which wraps `FilterChooser` in a `Popover` to allow it to expand
|
|
8
|
+
vertically when used in a `Toolbar`.
|
|
9
|
+
|
|
5
10
|
### 💥 Breaking Changes (upgrade difficulty: 🟢 TRIVIAL - minor upgrade to Hoist Core)
|
|
6
11
|
|
|
7
12
|
* Requires `hoist-core >= 30.1.0` with new APIs to support the consolidated Admin Console "Clients"
|
|
@@ -36,6 +41,9 @@
|
|
|
36
41
|
* Fixed drag-and-drop usability issues with the mobile `ColChooser`.
|
|
37
42
|
* Made `GridModel.defaultGroupSortFn` null-safe and improved type signature.
|
|
38
43
|
* Disable `dashCanvasAddViewButton` if there are no `menuItems` to show.
|
|
44
|
+
* Improvements to `@bindable` and `@persist` to handle lifecycle-related bugs. Note that previously
|
|
45
|
+
`@bindable` would work even if `makeObservable()` was not called, but this is no longer the case.
|
|
46
|
+
Please ensure that `makeObservable()` is called in your model's constructor when using `@bindable`.
|
|
39
47
|
|
|
40
48
|
### ⚙️ Typescript API Adjustments
|
|
41
49
|
|
|
@@ -11,7 +11,7 @@ import {grid} from '@xh/hoist/cmp/grid';
|
|
|
11
11
|
import {div, filler, hframe} from '@xh/hoist/cmp/layout';
|
|
12
12
|
import {creates, hoistCmp} from '@xh/hoist/core';
|
|
13
13
|
import {button, buttonGroup, colChooserButton, exportButton} from '@xh/hoist/desktop/cmp/button';
|
|
14
|
-
import {
|
|
14
|
+
import {popoverFilterChooser} from '@xh/hoist/desktop/cmp/filter';
|
|
15
15
|
import {formField} from '@xh/hoist/desktop/cmp/form';
|
|
16
16
|
import {groupingChooser} from '@xh/hoist/desktop/cmp/grouping';
|
|
17
17
|
import {dateInput, DateInputProps, select} from '@xh/hoist/desktop/cmp/input';
|
|
@@ -137,7 +137,7 @@ const filterChooserToggleButton = hoistCmp.factory<ActivityTrackingModel>(({mode
|
|
|
137
137
|
const filterBar = hoistCmp.factory<ActivityTrackingModel>(({model}) => {
|
|
138
138
|
return model.showFilterChooser
|
|
139
139
|
? toolbar(
|
|
140
|
-
|
|
140
|
+
popoverFilterChooser({
|
|
141
141
|
flex: 1,
|
|
142
142
|
enableClear: true
|
|
143
143
|
})
|
|
@@ -10,7 +10,7 @@ import {fragment, hframe, vframe} from '@xh/hoist/cmp/layout';
|
|
|
10
10
|
import {creates, hoistCmp} from '@xh/hoist/core';
|
|
11
11
|
import {button, colChooserButton} from '@xh/hoist/desktop/cmp/button';
|
|
12
12
|
import {errorMessage} from '@xh/hoist/cmp/error';
|
|
13
|
-
import {
|
|
13
|
+
import {popoverFilterChooser} from '@xh/hoist/desktop/cmp/filter';
|
|
14
14
|
import {switchInput} from '@xh/hoist/desktop/cmp/input';
|
|
15
15
|
import {panel} from '@xh/hoist/desktop/cmp/panel';
|
|
16
16
|
import {recordActionBar} from '@xh/hoist/desktop/cmp/record';
|
|
@@ -44,7 +44,7 @@ export const rolePanel = hoistCmp.factory({
|
|
|
44
44
|
selModel: gridModel.selModel
|
|
45
45
|
}),
|
|
46
46
|
'-',
|
|
47
|
-
|
|
47
|
+
popoverFilterChooser({flex: 1}),
|
|
48
48
|
'-',
|
|
49
49
|
switchInput({
|
|
50
50
|
bind: 'showInGroups',
|
|
@@ -79,6 +79,7 @@ export declare class FilterChooserModel extends HoistModel {
|
|
|
79
79
|
favoritesIsOpen: boolean;
|
|
80
80
|
unsupportedFilter: boolean;
|
|
81
81
|
inputRef: import("react").RefObject<HTMLElement> & import("react").RefCallback<HTMLElement>;
|
|
82
|
+
get tagCount(): number;
|
|
82
83
|
constructor({ fieldSpecs, fieldSpecDefaults, bind, valueSource, initialValue, initialFavorites, suggestFieldsWhenEmpty, sortFieldSuggestions, maxTags, maxResults, persistWith, introHelpText }?: FilterChooserConfig);
|
|
83
84
|
/**
|
|
84
85
|
* Set the value displayed by this control.
|
|
@@ -10,6 +10,8 @@ export interface FilterChooserProps extends HoistProps<FilterChooserModel>, Layo
|
|
|
10
10
|
disabled?: boolean;
|
|
11
11
|
/** True to show a "clear" button at the right of the control. Defaults to true. */
|
|
12
12
|
enableClear?: boolean;
|
|
13
|
+
/** True to show count of filter tags next to the left icon. */
|
|
14
|
+
displayCount?: boolean;
|
|
13
15
|
/** Icon to display inline on the left side of the input. */
|
|
14
16
|
leftIcon?: ReactElement;
|
|
15
17
|
/** Max-height of dropdown. Either a number in pixels or a valid CSS string, such as '80vh'. */
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import '@xh/hoist/desktop/register';
|
|
3
|
+
import './PopoverFilterChooser.scss';
|
|
4
|
+
import { FilterChooserProps } from './FilterChooser';
|
|
5
|
+
/**
|
|
6
|
+
* A wrapper around a FilterChooser that renders in a popover when opened, allowing it to expand
|
|
7
|
+
* vertically beyond the height of a toolbar.
|
|
8
|
+
* @see FilterChooser
|
|
9
|
+
*/
|
|
10
|
+
export declare const PopoverFilterChooser: import("react").FC<FilterChooserProps>, popoverFilterChooser: import("@xh/hoist/core").ElementFactory<FilterChooserProps>;
|
|
@@ -6,4 +6,4 @@ export declare function makeObservable(target: any, annotations?: AnnotationsMap
|
|
|
6
6
|
/**
|
|
7
7
|
* An enhanced version of the native mobx isObservableProp
|
|
8
8
|
*/
|
|
9
|
-
export declare function isObservableProp(target: any, propertyKey: PropertyKey):
|
|
9
|
+
export declare function isObservableProp(target: any, propertyKey: PropertyKey): boolean;
|
|
@@ -145,6 +145,10 @@ export class FilterChooserModel extends HoistModel {
|
|
|
145
145
|
@observable unsupportedFilter = false;
|
|
146
146
|
inputRef = createObservableRef<HTMLElement>();
|
|
147
147
|
|
|
148
|
+
get tagCount(): number {
|
|
149
|
+
return this.selectValue?.length ?? 0;
|
|
150
|
+
}
|
|
151
|
+
|
|
148
152
|
constructor({
|
|
149
153
|
fieldSpecs,
|
|
150
154
|
fieldSpecDefaults,
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Copyright © 2025 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
|
+
import {wait} from '@xh/hoist/promise';
|
|
8
|
+
import {observable} from 'mobx';
|
|
7
9
|
import {logError, throwIf} from '../utils/js';
|
|
8
10
|
import {HoistBaseClass, PersistableState, PersistenceProvider, PersistOptions} from './';
|
|
9
11
|
|
|
@@ -71,38 +73,38 @@ function createPersistDescriptor(
|
|
|
71
73
|
);
|
|
72
74
|
return descriptor;
|
|
73
75
|
}
|
|
74
|
-
const codeValue = descriptor.initializer
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// Initializer can be called multiple times when stacking decorators.
|
|
79
|
-
if (hasInitialized) return ret;
|
|
76
|
+
const codeValue = descriptor.initializer,
|
|
77
|
+
initializer = function () {
|
|
78
|
+
// codeValue undefined if no initial in-code value provided, otherwise call to get initial value.
|
|
79
|
+
let ret = codeValue?.call(this);
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
81
|
+
// Property is not available on the instance until after the next tick.
|
|
82
|
+
const propertyAvailable = observable.box(false),
|
|
83
|
+
persistOptions = {
|
|
84
|
+
path: property,
|
|
85
|
+
...PersistenceProvider.mergePersistOptions(this.persistWith, options)
|
|
86
|
+
};
|
|
87
|
+
PersistenceProvider.create({
|
|
88
|
+
persistOptions,
|
|
89
|
+
owner: this,
|
|
90
|
+
target: {
|
|
91
|
+
getPersistableState: () =>
|
|
92
|
+
new PersistableState(propertyAvailable.get() ? this[property] : ret),
|
|
93
|
+
setPersistableState: state => {
|
|
94
|
+
if (!propertyAvailable.get()) {
|
|
95
|
+
ret = state.value;
|
|
96
|
+
} else {
|
|
97
|
+
this[property] = state.value;
|
|
98
|
+
}
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
|
-
}
|
|
102
|
-
});
|
|
101
|
+
});
|
|
103
102
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
103
|
+
// Wait for next tick to ensure construction has completed and property has been made
|
|
104
|
+
// observable via makeObservable.
|
|
105
|
+
wait().thenAction(() => propertyAvailable.set(true));
|
|
106
|
+
|
|
107
|
+
return ret;
|
|
108
|
+
};
|
|
107
109
|
return {...descriptor, initializer};
|
|
108
110
|
}
|
|
@@ -16,6 +16,7 @@ import {withDefault} from '@xh/hoist/utils/js';
|
|
|
16
16
|
import {splitLayoutProps} from '@xh/hoist/utils/react';
|
|
17
17
|
import classNames from 'classnames';
|
|
18
18
|
import {isEmpty, sortBy} from 'lodash';
|
|
19
|
+
import {badge} from '@xh/hoist/cmp/badge';
|
|
19
20
|
import {ReactElement} from 'react';
|
|
20
21
|
import './FilterChooser.scss';
|
|
21
22
|
|
|
@@ -26,6 +27,8 @@ export interface FilterChooserProps extends HoistProps<FilterChooserModel>, Layo
|
|
|
26
27
|
disabled?: boolean;
|
|
27
28
|
/** True to show a "clear" button at the right of the control. Defaults to true. */
|
|
28
29
|
enableClear?: boolean;
|
|
30
|
+
/** True to show count of filter tags next to the left icon. */
|
|
31
|
+
displayCount?: boolean;
|
|
29
32
|
/** Icon to display inline on the left side of the input. */
|
|
30
33
|
leftIcon?: ReactElement;
|
|
31
34
|
/** Max-height of dropdown. Either a number in pixels or a valid CSS string, such as '80vh'. */
|
|
@@ -47,10 +50,23 @@ export const [FilterChooser, filterChooser] = hoistCmp.withFactory<FilterChooser
|
|
|
47
50
|
className: 'xh-filter-chooser',
|
|
48
51
|
render({model, className, ...props}, ref) {
|
|
49
52
|
const [layoutProps, chooserProps] = splitLayoutProps(props),
|
|
50
|
-
{
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
{
|
|
54
|
+
inputRef,
|
|
55
|
+
suggestFieldsWhenEmpty,
|
|
56
|
+
selectOptions,
|
|
57
|
+
unsupportedFilter,
|
|
58
|
+
favoritesIsOpen,
|
|
59
|
+
tagCount
|
|
60
|
+
} = model,
|
|
61
|
+
{
|
|
62
|
+
autoFocus,
|
|
63
|
+
enableClear,
|
|
64
|
+
displayCount,
|
|
65
|
+
leftIcon,
|
|
66
|
+
maxMenuHeight,
|
|
67
|
+
menuPlacement,
|
|
68
|
+
menuWidth
|
|
69
|
+
} = chooserProps,
|
|
54
70
|
disabled = unsupportedFilter || chooserProps.disabled,
|
|
55
71
|
placeholder = unsupportedFilter
|
|
56
72
|
? 'Unsupported filter (click to clear)'
|
|
@@ -61,42 +77,49 @@ export const [FilterChooser, filterChooser] = hoistCmp.withFactory<FilterChooser
|
|
|
61
77
|
className,
|
|
62
78
|
...layoutProps,
|
|
63
79
|
item: popover({
|
|
64
|
-
item:
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
80
|
+
item: hframe(
|
|
81
|
+
badge({
|
|
82
|
+
omit: !displayCount || tagCount < 1,
|
|
83
|
+
className: 'xh-filter-chooser__count',
|
|
84
|
+
item: tagCount
|
|
85
|
+
}),
|
|
86
|
+
select({
|
|
87
|
+
flex: 1,
|
|
88
|
+
height: layoutProps?.height,
|
|
89
|
+
bind: 'selectValue',
|
|
90
|
+
ref: inputRef,
|
|
69
91
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
92
|
+
autoFocus,
|
|
93
|
+
disabled,
|
|
94
|
+
menuPlacement,
|
|
95
|
+
menuWidth,
|
|
96
|
+
placeholder,
|
|
97
|
+
leftIcon: withDefault(leftIcon, Icon.filter()),
|
|
98
|
+
enableClear: withDefault(enableClear, true),
|
|
77
99
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
100
|
+
enableMulti: true,
|
|
101
|
+
queryFn: q => model.queryAsync(q),
|
|
102
|
+
options: selectOptions,
|
|
103
|
+
optionRenderer,
|
|
104
|
+
rsOptions: {
|
|
105
|
+
defaultOptions: suggestFieldsWhenEmpty,
|
|
106
|
+
openMenuOnClick: suggestFieldsWhenEmpty,
|
|
107
|
+
openMenuOnFocus: false,
|
|
108
|
+
isOptionDisabled: opt => opt.type === 'msg',
|
|
109
|
+
noOptionsMessage: () => null,
|
|
110
|
+
loadingMessage: () => null,
|
|
111
|
+
styles: {
|
|
112
|
+
menuList: base => ({
|
|
113
|
+
...base,
|
|
114
|
+
maxHeight: withDefault(maxMenuHeight, '50vh')
|
|
115
|
+
})
|
|
116
|
+
},
|
|
117
|
+
components: {
|
|
118
|
+
DropdownIndicator: () => favoritesIcon(model)
|
|
119
|
+
}
|
|
97
120
|
}
|
|
98
|
-
}
|
|
99
|
-
|
|
121
|
+
})
|
|
122
|
+
),
|
|
100
123
|
content: favoritesMenu(),
|
|
101
124
|
isOpen: favoritesIsOpen,
|
|
102
125
|
position: 'bottom-right',
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file belongs to Hoist, an application development toolkit
|
|
3
|
+
* developed by Extremely Heavy Industries (www.xh.io | info@xh.io)
|
|
4
|
+
*
|
|
5
|
+
* Copyright © 2025 Extremely Heavy Industries Inc.
|
|
6
|
+
*/
|
|
7
|
+
.xh-popover-filter-chooser {
|
|
8
|
+
& > .bp5-popover-target {
|
|
9
|
+
display: flex;
|
|
10
|
+
flex: 1;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Extra class names required to override the default styles of the popover
|
|
14
|
+
&__popover.bp5-popover.bp5-minimal {
|
|
15
|
+
margin-top: -15px !important;
|
|
16
|
+
box-shadow: none;
|
|
17
|
+
|
|
18
|
+
.bp5-popover-content {
|
|
19
|
+
background: transparent;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.xh-select__value-container--is-multi {
|
|
23
|
+
height: unset;
|
|
24
|
+
line-height: unset;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
&__filter-chooser {
|
|
29
|
+
.xh-select__value-container--is-multi {
|
|
30
|
+
overflow-y: hidden !important;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.xh-select {
|
|
34
|
+
.xh-select__control--is-disabled {
|
|
35
|
+
background: var(--xh-input-bg);
|
|
36
|
+
}
|
|
37
|
+
.xh-select__multi-value--is-disabled .xh-select__multi-value__label {
|
|
38
|
+
color: unset;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file belongs to Hoist, an application development toolkit
|
|
3
|
+
* developed by Extremely Heavy Industries (www.xh.io | info@xh.io)
|
|
4
|
+
*
|
|
5
|
+
* Copyright © 2025 Extremely Heavy Industries Inc.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {hoistCmp, HoistModel, lookup, useLocalModel, uses} from '@xh/hoist/core';
|
|
9
|
+
import {bindable, makeObservable} from '@xh/hoist/mobx';
|
|
10
|
+
import {box, hframe} from '@xh/hoist/cmp/layout';
|
|
11
|
+
import '@xh/hoist/desktop/register';
|
|
12
|
+
import {popover} from '@xh/hoist/kit/blueprint';
|
|
13
|
+
import {getLayoutProps} from '@xh/hoist/utils/react';
|
|
14
|
+
import './PopoverFilterChooser.scss';
|
|
15
|
+
import {filterChooser, FilterChooserProps} from './FilterChooser';
|
|
16
|
+
import {FilterChooserModel} from '@xh/hoist/cmp/filter';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A wrapper around a FilterChooser that renders in a popover when opened, allowing it to expand
|
|
20
|
+
* vertically beyond the height of a toolbar.
|
|
21
|
+
* @see FilterChooser
|
|
22
|
+
*/
|
|
23
|
+
export const [PopoverFilterChooser, popoverFilterChooser] =
|
|
24
|
+
hoistCmp.withFactory<FilterChooserProps>({
|
|
25
|
+
model: uses(FilterChooserModel),
|
|
26
|
+
className: 'xh-popover-filter-chooser',
|
|
27
|
+
render({model, className, ...props}, ref) {
|
|
28
|
+
const layoutProps = getLayoutProps(props),
|
|
29
|
+
impl = useLocalModel(PopoverFilterChooserLocalModel);
|
|
30
|
+
|
|
31
|
+
return box({
|
|
32
|
+
ref,
|
|
33
|
+
className,
|
|
34
|
+
...layoutProps,
|
|
35
|
+
item: popover({
|
|
36
|
+
isOpen: impl.popoverIsOpen,
|
|
37
|
+
popoverClassName: 'xh-popover-filter-chooser__popover',
|
|
38
|
+
item: hframe(
|
|
39
|
+
filterChooser({
|
|
40
|
+
model,
|
|
41
|
+
// Omit when popover is open to force update the inputRef
|
|
42
|
+
omit: impl.popoverIsOpen,
|
|
43
|
+
className: 'xh-popover-filter-chooser__filter-chooser',
|
|
44
|
+
displayCount: true,
|
|
45
|
+
...props,
|
|
46
|
+
disabled: true
|
|
47
|
+
})
|
|
48
|
+
),
|
|
49
|
+
content: filterChooser({
|
|
50
|
+
model,
|
|
51
|
+
displayCount: true,
|
|
52
|
+
...props
|
|
53
|
+
}),
|
|
54
|
+
matchTargetWidth: true,
|
|
55
|
+
minimal: true,
|
|
56
|
+
position: 'bottom',
|
|
57
|
+
onInteraction: open => {
|
|
58
|
+
if (open) {
|
|
59
|
+
impl.open();
|
|
60
|
+
} else {
|
|
61
|
+
impl.close();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
class PopoverFilterChooserLocalModel extends HoistModel {
|
|
70
|
+
override xhImpl = true;
|
|
71
|
+
|
|
72
|
+
@lookup(FilterChooserModel)
|
|
73
|
+
model: FilterChooserModel;
|
|
74
|
+
|
|
75
|
+
@bindable
|
|
76
|
+
popoverIsOpen: boolean = false;
|
|
77
|
+
|
|
78
|
+
get displaySelectValue() {
|
|
79
|
+
return this.model.selectValue[0];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
constructor() {
|
|
83
|
+
super();
|
|
84
|
+
makeObservable(this);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
open() {
|
|
88
|
+
this.popoverIsOpen = true;
|
|
89
|
+
|
|
90
|
+
// Focus and open the menu when rendered
|
|
91
|
+
this.addReaction({
|
|
92
|
+
when: () => !!this.model.inputRef.current,
|
|
93
|
+
run: () => {
|
|
94
|
+
const inputRef = this.model.inputRef.current;
|
|
95
|
+
inputRef.focus();
|
|
96
|
+
(inputRef as any).reactSelectRef.current.select.onMenuOpen();
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
close() {
|
|
102
|
+
this.popoverIsOpen = false;
|
|
103
|
+
}
|
|
104
|
+
}
|
package/mobx/decorators.ts
CHANGED
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
* Copyright © 2025 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
7
|
import {upperFirst} from 'lodash';
|
|
8
|
-
import {observable, runInAction} from 'mobx';
|
|
9
|
-
import {getOrCreate} from '../utils/js';
|
|
10
8
|
|
|
11
9
|
/**
|
|
12
10
|
* Decorator to mark a property as observable and also provide a simple MobX action of the
|
|
@@ -40,40 +38,14 @@ function createBindable(target, name, descriptor, isRef) {
|
|
|
40
38
|
Object.defineProperty(target, setterName, {value});
|
|
41
39
|
}
|
|
42
40
|
|
|
43
|
-
// 2)
|
|
44
|
-
|
|
45
|
-
propName = `_${name}_bindable`,
|
|
46
|
-
valName = `_${name}_bindable_value`;
|
|
47
|
-
Object.defineProperty(target, propName, {
|
|
48
|
-
get() {
|
|
49
|
-
return getOrCreate(this, valName, () => {
|
|
50
|
-
const initVal = initializer?.call(this);
|
|
51
|
-
return isRef ? observable.box(initVal, {deep: false}) : observable.box(initVal);
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
// 3) Create the descriptor for a getter/setter pair..
|
|
57
|
-
descriptor = {
|
|
58
|
-
get() {
|
|
59
|
-
return this[propName].get();
|
|
60
|
-
},
|
|
61
|
-
set(v) {
|
|
62
|
-
runInAction(() => this[propName].set(v));
|
|
63
|
-
},
|
|
64
|
-
enumerable: true,
|
|
65
|
-
configurable: true
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
// 4) Record on class, so we can later create on *instance* in makeObservable.
|
|
69
|
-
// (Be sure to create cloned list for *this* particular class.)
|
|
41
|
+
// 2) Record on class, so we can later create on *instance* in makeObservable.
|
|
42
|
+
// (Be sure to create cloned list since this will exist on prototype superclasses of this class)
|
|
70
43
|
const key = '_xhBindableProperties';
|
|
71
44
|
if (!target.hasOwnProperty(key)) {
|
|
72
45
|
target[key] = {...target[key]};
|
|
73
46
|
}
|
|
74
|
-
target[key][name] =
|
|
47
|
+
target[key][name] = {isRef};
|
|
75
48
|
|
|
76
|
-
//
|
|
77
|
-
// late, the non-enumerable property will still be available.)
|
|
49
|
+
// 3) Return original descriptor.
|
|
78
50
|
return descriptor;
|
|
79
51
|
}
|
package/mobx/overrides.ts
CHANGED
|
@@ -9,7 +9,9 @@ import {
|
|
|
9
9
|
AnnotationsMap,
|
|
10
10
|
CreateObservableOptions,
|
|
11
11
|
makeObservable as baseMakeObservable,
|
|
12
|
-
isObservableProp as baseIsObservableProp
|
|
12
|
+
isObservableProp as baseIsObservableProp,
|
|
13
|
+
observable,
|
|
14
|
+
runInAction
|
|
13
15
|
} from 'mobx';
|
|
14
16
|
|
|
15
17
|
/**
|
|
@@ -21,10 +23,21 @@ export function makeObservable(
|
|
|
21
23
|
options?: CreateObservableOptions
|
|
22
24
|
) {
|
|
23
25
|
// Finish creating 'bindable' properties for this instance.
|
|
24
|
-
// Do here to ensure it's enumerable on *instance*
|
|
25
26
|
const bindables = target._xhBindableProperties;
|
|
26
|
-
forEach(bindables, (
|
|
27
|
-
|
|
27
|
+
forEach(bindables, ({isRef}, name) => {
|
|
28
|
+
const propName = `_${name}_bindable`,
|
|
29
|
+
initVal = target[name];
|
|
30
|
+
target[propName] = isRef ? observable.box(initVal, {deep: false}) : observable.box(initVal);
|
|
31
|
+
Object.defineProperty(target, name, {
|
|
32
|
+
get() {
|
|
33
|
+
return this[propName].get();
|
|
34
|
+
},
|
|
35
|
+
set(v) {
|
|
36
|
+
runInAction(() => this[propName].set(v));
|
|
37
|
+
},
|
|
38
|
+
enumerable: true,
|
|
39
|
+
configurable: true
|
|
40
|
+
});
|
|
28
41
|
});
|
|
29
42
|
|
|
30
43
|
return baseMakeObservable(target, annotations, options);
|
|
@@ -33,8 +46,8 @@ export function makeObservable(
|
|
|
33
46
|
/**
|
|
34
47
|
* An enhanced version of the native mobx isObservableProp
|
|
35
48
|
*/
|
|
36
|
-
export function isObservableProp(target: any, propertyKey: PropertyKey) {
|
|
49
|
+
export function isObservableProp(target: any, propertyKey: PropertyKey): boolean {
|
|
37
50
|
return (
|
|
38
|
-
baseIsObservableProp(target, propertyKey) || target?._xhBindableProperties?.[propertyKey]
|
|
51
|
+
baseIsObservableProp(target, propertyKey) || !!target?._xhBindableProperties?.[propertyKey]
|
|
39
52
|
);
|
|
40
53
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xh/hoist",
|
|
3
|
-
"version": "73.0.0-SNAPSHOT.
|
|
3
|
+
"version": "73.0.0-SNAPSHOT.1746830066260",
|
|
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",
|