@xh/hoist 73.0.0-SNAPSHOT.1744142528681 → 73.0.0-SNAPSHOT.1744144713361

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
@@ -2,6 +2,11 @@
2
2
 
3
3
  ## v73.0.0-SNAPSHOT - unreleased
4
4
 
5
+ ### 🎁 New Features
6
+
7
+ `ViewManagerConfig` takes new key `viewRouteParam` to allow ViewManagers implemented with routing to
8
+ have the view buttons on their menu items be right clickable/Ctrl+ Click to open views in new tabs or windows.
9
+
5
10
  ## v72.3.0 - 2025-04-08
6
11
 
7
12
  ### 🎁 New Features
@@ -85,6 +85,12 @@ export interface ViewManagerConfig {
85
85
  * Optional user-facing display name for describing global views. Defaults to 'global'
86
86
  */
87
87
  globalDisplayName?: string;
88
+ /**
89
+ * Optional key used as route param for view tokens. Specify if you have customized your
90
+ * ViewManager implementation to be routable, and you want users to be able to Ctrl+Click or
91
+ * ContextMenu Click to open views from the view menu in new tabs or windows.
92
+ */
93
+ viewRouteParam?: string;
88
94
  }
89
95
  /**
90
96
  * ViewManagerModel coordinates the loading, saving, and management of user-defined bundles of
@@ -121,6 +127,7 @@ export declare class ViewManagerModel<T = PlainObject> extends HoistModel {
121
127
  readonly instance: string;
122
128
  readonly typeDisplayName: string;
123
129
  readonly globalDisplayName: string;
130
+ readonly viewRouteParam: string;
124
131
  readonly enableAutoSave: boolean;
125
132
  readonly enableDefault: boolean;
126
133
  readonly enableGlobal: boolean;
@@ -123,6 +123,13 @@ export interface ViewManagerConfig {
123
123
  * Optional user-facing display name for describing global views. Defaults to 'global'
124
124
  */
125
125
  globalDisplayName?: string;
126
+
127
+ /**
128
+ * Optional key used as route param for view tokens. Specify if you have customized your
129
+ * ViewManager implementation to be routable, and you want users to be able to Ctrl+Click or
130
+ * ContextMenu Click to open views from the view menu in new tabs or windows.
131
+ */
132
+ viewRouteParam?: string;
126
133
  }
127
134
 
128
135
  /**
@@ -165,6 +172,7 @@ export class ViewManagerModel<T = PlainObject> extends HoistModel {
165
172
  readonly instance: string;
166
173
  readonly typeDisplayName: string;
167
174
  readonly globalDisplayName: string;
175
+ readonly viewRouteParam: string;
168
176
  readonly enableAutoSave: boolean;
169
177
  readonly enableDefault: boolean;
170
178
  readonly enableGlobal: boolean;
@@ -283,6 +291,7 @@ export class ViewManagerModel<T = PlainObject> extends HoistModel {
283
291
  instance = 'default',
284
292
  typeDisplayName,
285
293
  globalDisplayName = 'global',
294
+ viewRouteParam,
286
295
  manageGlobal = false,
287
296
  enableAutoSave = true,
288
297
  enableDefault = true,
@@ -296,13 +305,19 @@ export class ViewManagerModel<T = PlainObject> extends HoistModel {
296
305
 
297
306
  throwIf(
298
307
  !enableDefault && !initialViewSpec,
299
- "ViewManagerModel requires 'initialViewSpec' if `enableDefault` is false."
308
+ "ViewManagerModel requires 'initialViewSpec' if 'enableDefault' is false."
309
+ );
310
+
311
+ throwIf(
312
+ viewRouteParam && isNil(XH.routerState),
313
+ "Cannot use 'viewRouteParam' if your app does not define a router."
300
314
  );
301
315
 
302
316
  this.type = type;
303
317
  this.instance = instance;
304
318
  this.typeDisplayName = lowerCase(typeDisplayName ?? genDisplayName(type));
305
319
  this.globalDisplayName = globalDisplayName;
320
+ this.viewRouteParam = viewRouteParam;
306
321
  this.manageGlobal = executeIfFunction(manageGlobal) ?? false;
307
322
  this.enableDefault = enableDefault;
308
323
  this.enableGlobal = enableGlobal;
@@ -5,12 +5,12 @@
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
7
 
8
- import {hoistCmp} from '@xh/hoist/core';
8
+ import {hoistCmp, XH} from '@xh/hoist/core';
9
9
  import {ViewManagerModel, ViewInfo} from '@xh/hoist/cmp/viewmanager';
10
10
  import {switchInput} from '@xh/hoist/desktop/cmp/input';
11
11
  import {Icon} from '@xh/hoist/icon';
12
12
  import {menu, menuDivider, menuItem} from '@xh/hoist/kit/blueprint';
13
- import {pluralize} from '@xh/hoist/utils/js';
13
+ import {consumeEvent, pluralize} from '@xh/hoist/utils/js';
14
14
  import {Dictionary} from 'express-serve-static-core';
15
15
  import {each, filter, groupBy, isEmpty, orderBy, some, startCase} from 'lodash';
16
16
  import {ReactNode} from 'react';
@@ -157,17 +157,34 @@ function getGroupedMenuItems(
157
157
 
158
158
  function viewMenuItem(view: ViewInfo, model: ViewManagerModel): ReactNode {
159
159
  const icon = view.isCurrentView ? Icon.check() : Icon.placeholder(),
160
- title = [];
160
+ title = [],
161
+ usingRouting = !!(XH.routerState && model.viewRouteParam);
161
162
 
162
163
  if (!view.isOwned && view.owner) title.push(view.owner);
163
164
  if (view.description) title.push(view.description);
164
165
 
166
+ const href = usingRouting
167
+ ? XH.router.buildUrl(XH.routerState.name, {
168
+ ...XH.routerState.params,
169
+ [model.viewRouteParam]: view.token
170
+ })
171
+ : undefined;
172
+
165
173
  return menuItem({
166
174
  className: 'xh-view-manager__menu-item',
167
175
  key: view.token,
168
176
  text: view.name,
169
177
  title: title.join(' | '),
170
178
  icon,
171
- onClick: () => model.selectViewAsync(view).catchDefault()
179
+ href,
180
+ onClick: e => {
181
+ if (!usingRouting || (e.button === 0 && !e.ctrlKey && !e.metaKey)) {
182
+ consumeEvent(e);
183
+ model.selectViewAsync(view).catchDefault();
184
+ return false;
185
+ }
186
+
187
+ return true;
188
+ }
172
189
  });
173
190
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xh/hoist",
3
- "version": "73.0.0-SNAPSHOT.1744142528681",
3
+ "version": "73.0.0-SNAPSHOT.1744144713361",
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",