@xh/hoist 73.0.0-SNAPSHOT.1746829743606 → 73.0.0-SNAPSHOT.1746837312368

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
@@ -11,7 +11,7 @@
11
11
  applicable. This did not previously have any effect, but is required now for the superclass to
12
12
  initialize a new `ViewManagerModel`.
13
13
  * For clarity, [here is where Toolbox makes that call](https://github.com/xh/toolbox/blob/f15a8018ce36c2ae998b45724b48a16320b88e49/client-app/src/admin/AppModel.ts#L12).
14
-
14
+ * Requires call to `makeObservable(this)` in model constructors with `@bindable` (see below).
15
15
 
16
16
  ### 🎁 New Features
17
17
 
@@ -27,7 +27,8 @@
27
27
  the "skip weekends" option.
28
28
  * Client Error reports and user feedback have also been consolidated into the new tracking
29
29
  system for more integrated and powerful reporting.
30
-
30
+ * Added new `PopoverFilterChooser` component - wraps `FilterChooser` in a `Popover` to allow it to
31
+ expand vertically when used in a `Toolbar` or other space-constrained, single-line layout.
31
32
  * Updated `FormModel` to support `persistWith` for storing and recalling its values, including
32
33
  developer options to persist all or a provided subset of fields.
33
34
 
@@ -35,17 +36,13 @@
35
36
 
36
37
  * Fixed drag-and-drop usability issues with the mobile `ColChooser`.
37
38
  * Made `GridModel.defaultGroupSortFn` null-safe and improved type signature.
38
- * Disable `dashCanvasAddViewButton` if there are no `menuItems` to show.
39
- * Improvements to `@bindable` and `@persist` to handle lifecycle-related bugs. Note that previously
39
+ * Disabled `dashCanvasAddViewButton` if there are no `menuItems` to show.
40
+ * Hardened `@bindable` and `@persist` to handle lifecycle-related bugs. Note that previously
40
41
  `@bindable` would work even if `makeObservable()` was not called, but this is no longer the case.
41
- Please ensure that `makeObservable()` is called in your model's constructor when using `@bindable`.
42
-
43
- ### ⚙️ Typescript API Adjustments
44
-
45
- * Corrected `GridGroupSortFn` param types.
46
- * Corrected `StoreCountLabelProps` interface.
47
- * Corrected `textAlign` type in `DateInputProps`, `NumberInputProps` `SearchInputProps` and
48
- `TextInputProps`.
42
+ Please ensure you call `makeObservable(this)` in your model's constructor when using `@bindable`!
43
+ * Improved client `WebSocketService` heartbeat to check that it has been receiving inbound messages
44
+ from the server, not just successfully sending outbound heartbeats. Will auto-reconnect if needed
45
+ in a newly throttled/managed manner.
49
46
 
50
47
  ### ⚙️ Technical
51
48
 
@@ -59,9 +56,12 @@
59
56
  as the server - would result in a false positive for an upgrade. The two should always match.
60
57
  * Calls to `Promise.track()` that are rejected with an exception will be tracked with new
61
58
  severity level of `TrackSeverity.ERROR`.
62
- * Improved client `WebSocketService` heartbeat to check that it has been receiving inbound messages
63
- from the server, not just successfully sending outbound heartbeats.
64
- * Improved client `WebSocketService` to throttle its reconnect attempts.
59
+
60
+ ### ⚙️ Typescript API Adjustments
61
+
62
+ * Corrected `GridGroupSortFn` param types.
63
+ * Corrected `StoreCountLabelProps` interface.
64
+ * Corrected `textAlign` type across several `HoistInput` prop interfaces.
65
65
 
66
66
  ## v72.5.1 - 2025-04-15
67
67
 
@@ -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 {filterChooser} from '@xh/hoist/desktop/cmp/filter';
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
- filterChooser({
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 {filterChooser} from '@xh/hoist/desktop/cmp/filter';
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
- filterChooser({flex: 1}),
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>;
@@ -1,2 +1,3 @@
1
1
  export * from './FilterChooser';
2
+ export * from './PopoverFilterChooser';
2
3
  export * from '@xh/hoist/cmp/filter';
@@ -27,6 +27,10 @@ export interface NavigatorConfig {
27
27
  * See enum for description of supported modes.
28
28
  */
29
29
  refreshMode?: RefreshMode;
30
+ /**
31
+ * Base route name for this navigator, with the route for each page being "[route]/[page.id]".
32
+ */
33
+ route?: string;
30
34
  }
31
35
  /**
32
36
  * Model for handling stack-based navigation between pages.
@@ -34,6 +38,8 @@ export interface NavigatorConfig {
34
38
  */
35
39
  export declare class NavigatorModel extends HoistModel {
36
40
  disableAppRefreshButton: boolean;
41
+ readonly route: string;
42
+ readonly routePrefix: string;
37
43
  stack: PageModel[];
38
44
  pages: PageConfig[];
39
45
  track: boolean;
@@ -49,7 +55,7 @@ export declare class NavigatorModel extends HoistModel {
49
55
  get activePageIdx(): number;
50
56
  get allowSlideNext(): boolean;
51
57
  get allowSlidePrev(): boolean;
52
- constructor({ pages, track, pullDownToRefresh, transitionMs, renderMode, refreshMode }: NavigatorConfig);
58
+ constructor({ pages, route, track, pullDownToRefresh, transitionMs, renderMode, refreshMode }: NavigatorConfig);
53
59
  /**
54
60
  * @param callback - function to execute (once) after the next page transition.
55
61
  */
@@ -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,
@@ -144,10 +144,10 @@ export class TabContainerModel extends HoistModel implements Persistable<{active
144
144
  this.refreshContextModel.xhImpl = xhImpl;
145
145
 
146
146
  if (route) {
147
- if (XH.isMobileApp) {
148
- this.logWarn('TabContainer routing is not supported for mobile applications.');
149
- return;
150
- }
147
+ // if (XH.isMobileApp) {
148
+ // this.logWarn('TabContainer routing is not supported for mobile applications.');
149
+ // return;
150
+ // }
151
151
 
152
152
  this.addReaction({
153
153
  track: () => XH.routerState,
@@ -10,6 +10,11 @@
10
10
  display: flex;
11
11
  flex: 1;
12
12
  }
13
+
14
+ &__count {
15
+ margin: 7px 4px;
16
+ align-self: start;
17
+ }
13
18
  }
14
19
 
15
20
  .xh-filter-chooser-option {
@@ -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
- {inputRef, suggestFieldsWhenEmpty, selectOptions, unsupportedFilter, favoritesIsOpen} =
51
- model,
52
- {autoFocus, enableClear, leftIcon, maxMenuHeight, menuPlacement, menuWidth} =
53
- chooserProps,
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: select({
65
- flex: 1,
66
- height: layoutProps?.height,
67
- bind: 'selectValue',
68
- ref: inputRef,
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
- autoFocus,
71
- disabled,
72
- menuPlacement,
73
- menuWidth,
74
- placeholder,
75
- leftIcon: withDefault(leftIcon, Icon.filter()),
76
- enableClear: withDefault(enableClear, true),
92
+ autoFocus,
93
+ disabled,
94
+ menuPlacement,
95
+ menuWidth,
96
+ placeholder,
97
+ leftIcon: withDefault(leftIcon, Icon.filter()),
98
+ enableClear: withDefault(enableClear, true),
77
99
 
78
- enableMulti: true,
79
- queryFn: q => model.queryAsync(q),
80
- options: selectOptions,
81
- optionRenderer,
82
- rsOptions: {
83
- defaultOptions: suggestFieldsWhenEmpty,
84
- openMenuOnClick: suggestFieldsWhenEmpty,
85
- openMenuOnFocus: false,
86
- isOptionDisabled: opt => opt.type === 'msg',
87
- noOptionsMessage: () => null,
88
- loadingMessage: () => null,
89
- styles: {
90
- menuList: base => ({
91
- ...base,
92
- maxHeight: withDefault(maxMenuHeight, '50vh')
93
- })
94
- },
95
- components: {
96
- DropdownIndicator: () => favoritesIcon(model)
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
+ }
@@ -1,2 +1,3 @@
1
1
  export * from './FilterChooser';
2
+ export * from './PopoverFilterChooser';
2
3
  export * from '@xh/hoist/cmp/filter';
@@ -44,6 +44,11 @@ export interface NavigatorConfig {
44
44
  * See enum for description of supported modes.
45
45
  */
46
46
  refreshMode?: RefreshMode;
47
+
48
+ /**
49
+ * Base route name for this navigator, with the route for each page being "[route]/[page.id]".
50
+ */
51
+ route?: string;
47
52
  }
48
53
 
49
54
  /**
@@ -53,6 +58,9 @@ export interface NavigatorConfig {
53
58
  export class NavigatorModel extends HoistModel {
54
59
  @bindable disableAppRefreshButton: boolean;
55
60
 
61
+ readonly route: string;
62
+ readonly routePrefix: string;
63
+
56
64
  @bindable.ref
57
65
  stack: PageModel[] = [];
58
66
 
@@ -89,6 +97,7 @@ export class NavigatorModel extends HoistModel {
89
97
 
90
98
  constructor({
91
99
  pages,
100
+ route,
92
101
  track = false,
93
102
  pullDownToRefresh = true,
94
103
  transitionMs = 500,
@@ -101,6 +110,9 @@ export class NavigatorModel extends HoistModel {
101
110
  ensureNotEmpty(pages, 'NavigatorModel needs at least one page.');
102
111
  ensureUniqueBy(pages, 'id', 'Multiple NavigatorModel PageModels have the same id.');
103
112
 
113
+ this.route = route ?? '';
114
+ this.routePrefix = route ? route.substring(0, route.lastIndexOf('.') + 1) : '';
115
+
104
116
  this.pages = pages;
105
117
  this.track = track;
106
118
  this.pullDownToRefresh = pullDownToRefresh;
@@ -209,7 +221,7 @@ export class NavigatorModel extends HoistModel {
209
221
  this.stack = this.stack.slice(0, this._swiper.activeIndex + 1);
210
222
 
211
223
  // 2) Sync route to match the current page stack
212
- const newRouteName = this.stack.map(it => it.id).join('.'),
224
+ const newRouteName = this.routePrefix + this.stack.map(it => it.id).join('.'),
213
225
  newRouteParams = mergeDeep({}, ...this.stack.map(it => it.props));
214
226
 
215
227
  XH.navigate(newRouteName, newRouteParams);
@@ -226,16 +238,17 @@ export class NavigatorModel extends HoistModel {
226
238
  };
227
239
 
228
240
  private onRouteChange(init: boolean = false) {
229
- if (!this._swiper || !XH.routerState) return;
241
+ const {route: myRoute, routePrefix: myRoutePrefix, _swiper} = this;
242
+ if (!XH.routerState || (myRoute && !XH.router.isActive(myRoute)) || !_swiper) return;
230
243
 
231
- // Break the current route name into parts, and collect any params for each part.
232
- // Use meta.params to determine which params are associated with each route part.
233
- // Save these params to use as props for the page.
244
+ // Break the current route name into parts, only looking at our part of it (myRoute and below).
245
+ // Collect any params for each part. Use meta.params to determine which params are associated
246
+ // with each route part. Save these params to use as props for the page.
234
247
  const {meta, name, params} = XH.routerState,
235
- parts = name.split('.');
248
+ parts = name.replace(myRoutePrefix, '').split('.');
236
249
 
237
250
  const routeParts = parts.map((id, idx) => {
238
- const metaKey = parts.slice(0, idx + 1).join('.'),
251
+ const metaKey = myRoutePrefix + parts.slice(0, idx + 1).join('.'),
239
252
  props = {};
240
253
 
241
254
  // Extract props for this part
@@ -262,7 +275,7 @@ export class NavigatorModel extends HoistModel {
262
275
  // we drop the rest of the route and redirect to the route so far
263
276
  if (init && pageModelCfg.disableDirectLink) {
264
277
  const completedRouteParts = routeParts.slice(0, i),
265
- newRouteName = completedRouteParts.map(it => it.id).join('.'),
278
+ newRouteName = myRoutePrefix + completedRouteParts.map(it => it.id).join('.'),
266
279
  newRouteParams = mergeDeep({}, ...completedRouteParts.map(it => it.props));
267
280
 
268
281
  XH.navigate(newRouteName, newRouteParams, {replace: true});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xh/hoist",
3
- "version": "73.0.0-SNAPSHOT.1746829743606",
3
+ "version": "73.0.0-SNAPSHOT.1746837312368",
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",