@opengeni/react 0.52.1 → 0.57.0
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/README.md +48 -0
- package/dist/artifacts.d.ts +1 -1
- package/dist/artifacts.js +43 -14
- package/dist/artifacts.js.map +1 -1
- package/dist/{chunk-ROIRTM37.js → chunk-5UQPNLIO.js} +6 -6
- package/dist/{chunk-JR3QFY6B.js → chunk-6KLX2RH5.js} +49 -2
- package/dist/chunk-6KLX2RH5.js.map +1 -0
- package/dist/{chunk-FWS3KC3Z.js → chunk-B6WPZSTT.js} +104 -104
- package/dist/{chunk-FWS3KC3Z.js.map → chunk-B6WPZSTT.js.map} +1 -1
- package/dist/{chunk-HDBG7XGO.js → chunk-C5ZPSSS5.js} +50 -1
- package/dist/chunk-C5ZPSSS5.js.map +1 -0
- package/dist/{chunk-X4S56Y2H.js → chunk-HA46CYQK.js} +135 -11
- package/dist/chunk-HA46CYQK.js.map +1 -0
- package/dist/{chunk-724BW4TW.js → chunk-IGC6A2ZI.js} +2 -2
- package/dist/chunk-LLOLUHVG.js +5937 -0
- package/dist/chunk-LLOLUHVG.js.map +1 -0
- package/dist/{chunk-WYA65Y3F.js → chunk-MKPIAGVL.js} +13 -3
- package/dist/chunk-MKPIAGVL.js.map +1 -0
- package/dist/chunk-R3AZOAB5.js +933 -0
- package/dist/chunk-R3AZOAB5.js.map +1 -0
- package/dist/{chunk-23EJ676W.js → chunk-XBZWOM2K.js} +9 -4
- package/dist/chunk-XBZWOM2K.js.map +1 -0
- package/dist/{chunk-JAGDUCZQ.js → chunk-Y7OEDUJ5.js} +17 -13
- package/dist/chunk-Y7OEDUJ5.js.map +1 -0
- package/dist/client.d.ts +6 -4
- package/dist/components/artifacts/index.d.ts +1 -0
- package/dist/components/artifacts/published-html-artifact-frame.d.ts +14 -0
- package/dist/components/browser-input.d.ts +7 -0
- package/dist/components/browser-viewer.d.ts +5 -4
- package/dist/components/computer-viewer.d.ts +2 -1
- package/dist/components/desktop-viewer.d.ts +26 -2
- package/dist/components/interaction-intervention-banner.d.ts +11 -0
- package/dist/components/sandbox-terminal.d.ts +4 -1
- package/dist/components/sandbox-workspace.d.ts +3 -0
- package/dist/composer.js +6 -6
- package/dist/hooks/use-auth-runs.d.ts +32 -0
- package/dist/hooks/use-browser-downloads.d.ts +25 -0
- package/dist/hooks/use-browser-identities.d.ts +5 -1
- package/dist/hooks/use-browser-session.d.ts +2 -1
- package/dist/hooks/use-browser-sessions.d.ts +1 -1
- package/dist/hooks/use-channels.d.ts +26 -0
- package/dist/hooks/use-computer-frame-stream.d.ts +1 -1
- package/dist/hooks/use-computer-session.d.ts +2 -1
- package/dist/hooks/use-computer-sessions.d.ts +1 -1
- package/dist/hooks/use-desktop-stream.d.ts +4 -0
- package/dist/hooks/use-interaction-interventions.d.ts +27 -0
- package/dist/hooks/use-interaction-invalidation.d.ts +19 -0
- package/dist/hooks/use-network-routes.d.ts +25 -0
- package/dist/hooks/use-site-auth-connections.d.ts +25 -0
- package/dist/hooks/use-supergrok-accounts.d.ts +26 -0
- package/dist/hooks/use-terminal-stream.d.ts +3 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1220 -1545
- package/dist/index.js.map +1 -1
- package/dist/interaction.d.ts +13 -3
- package/dist/interaction.js +520 -6
- package/dist/interaction.js.map +1 -1
- package/dist/interactive-workbench-viewers-TOHBXJEE.js +15 -0
- package/dist/lib/host-platform.d.ts +5 -0
- package/dist/lib/relay-wire.d.ts +20 -1
- package/dist/machines.js +3 -3
- package/dist/model-policy.d.ts +1 -1
- package/dist/model-policy.js +1 -1
- package/dist/provider.d.ts +3 -2
- package/dist/realtime/realtime-control.d.ts +2 -2
- package/dist/realtime.js +36 -9
- package/dist/realtime.js.map +1 -1
- package/dist/session-context.d.ts +10 -2
- package/dist/session-ui.js +3 -3
- package/dist/session.js +11 -11
- package/dist/timeline/types.d.ts +5 -0
- package/package.json +2 -2
- package/src/artifacts.ts +3 -0
- package/src/client.ts +73 -3
- package/src/components/artifacts/index.ts +5 -0
- package/src/components/artifacts/published-html-artifact-frame.tsx +38 -0
- package/src/components/browser-input.ts +65 -0
- package/src/components/browser-viewer.tsx +1287 -177
- package/src/components/computer-viewer.tsx +611 -114
- package/src/components/desktop-viewer.tsx +114 -1
- package/src/components/interaction-intervention-banner.tsx +99 -0
- package/src/components/machines/machine-detail.tsx +1 -1
- package/src/components/model-policy-picker.tsx +15 -0
- package/src/components/sandbox-terminal.tsx +24 -7
- package/src/components/sandbox-workspace.tsx +42 -4
- package/src/components/workspace-dock.tsx +59 -5
- package/src/hooks/use-attached-browsers.ts +13 -11
- package/src/hooks/use-auth-runs.ts +278 -0
- package/src/hooks/use-browser-downloads.ts +218 -0
- package/src/hooks/use-browser-frame-stream.ts +168 -59
- package/src/hooks/use-browser-identities.ts +47 -6
- package/src/hooks/use-browser-session.ts +94 -27
- package/src/hooks/use-browser-sessions.ts +19 -14
- package/src/hooks/use-channels.ts +99 -0
- package/src/hooks/use-computer-frame-stream.ts +184 -61
- package/src/hooks/use-computer-session.ts +22 -2
- package/src/hooks/use-computer-sessions.ts +19 -13
- package/src/hooks/use-desktop-stream.ts +39 -7
- package/src/hooks/use-interaction-interventions.ts +242 -0
- package/src/hooks/use-interaction-invalidation.ts +66 -0
- package/src/hooks/use-machine-chip.ts +13 -3
- package/src/hooks/use-network-routes.ts +214 -0
- package/src/hooks/use-site-auth-connections.ts +226 -0
- package/src/hooks/use-supergrok-accounts.ts +81 -0
- package/src/hooks/use-terminal-stream.ts +288 -55
- package/src/index.ts +8 -0
- package/src/interaction.ts +30 -0
- package/src/lib/host-platform.ts +10 -0
- package/src/lib/relay-wire.ts +43 -4
- package/src/lib/terminal-capability.ts +1 -1
- package/src/model-policy.ts +19 -4
- package/src/provider.tsx +133 -1
- package/src/realtime/realtime-control.tsx +34 -6
- package/src/session-context.ts +66 -1
- package/src/timeline/activity-rail.tsx +6 -0
- package/src/timeline/projection.ts +58 -0
- package/src/timeline/types.ts +2 -0
- package/styles/compiled.css +64 -6
- package/dist/chunk-23EJ676W.js.map +0 -1
- package/dist/chunk-6BBWWOOU.js +0 -82
- package/dist/chunk-6BBWWOOU.js.map +0 -1
- package/dist/chunk-7I2KB3OK.js +0 -3895
- package/dist/chunk-7I2KB3OK.js.map +0 -1
- package/dist/chunk-HDBG7XGO.js.map +0 -1
- package/dist/chunk-JAGDUCZQ.js.map +0 -1
- package/dist/chunk-JR3QFY6B.js.map +0 -1
- package/dist/chunk-WYA65Y3F.js.map +0 -1
- package/dist/chunk-X4S56Y2H.js.map +0 -1
- package/dist/interactive-workbench-viewers-KHNOHWQE.js +0 -13
- /package/dist/{chunk-ROIRTM37.js.map → chunk-5UQPNLIO.js.map} +0 -0
- /package/dist/{chunk-724BW4TW.js.map → chunk-IGC6A2ZI.js.map} +0 -0
- /package/dist/{interactive-workbench-viewers-KHNOHWQE.js.map → interactive-workbench-viewers-TOHBXJEE.js.map} +0 -0
package/src/client.ts
CHANGED
|
@@ -62,6 +62,12 @@ export type SessionClientLike = Pick<
|
|
|
62
62
|
| "deleteEnvironment"
|
|
63
63
|
| "setEnvironmentVariable"
|
|
64
64
|
| "deleteEnvironmentVariable"
|
|
65
|
+
// Channels (rail organization)
|
|
66
|
+
| "listChannels"
|
|
67
|
+
| "createChannel"
|
|
68
|
+
| "updateChannel"
|
|
69
|
+
| "deleteChannel"
|
|
70
|
+
| "updateSessionChannel"
|
|
65
71
|
// Rigs
|
|
66
72
|
| "listRigs"
|
|
67
73
|
| "createRig"
|
|
@@ -94,6 +100,7 @@ export type SessionClientLike = Pick<
|
|
|
94
100
|
| "getWorkspaceModelCatalog"
|
|
95
101
|
| "listWorkspaceControlEvents"
|
|
96
102
|
| "streamWorkspaceControlEvents"
|
|
103
|
+
| "streamWorkspaceInteractionRevisions"
|
|
97
104
|
| "getBillingUsage"
|
|
98
105
|
// Stream surfacing (Phase 5): capability negotiation + viewer lifecycle
|
|
99
106
|
| "getClientConfig"
|
|
@@ -103,14 +110,37 @@ export type SessionClientLike = Pick<
|
|
|
103
110
|
| "heartbeatViewer"
|
|
104
111
|
| "detachViewer"
|
|
105
112
|
// Browser/Computer interaction resources
|
|
113
|
+
| "listNetworkRoutes"
|
|
114
|
+
| "getNetworkRoute"
|
|
115
|
+
| "createNetworkRoute"
|
|
116
|
+
| "updateNetworkRoute"
|
|
117
|
+
| "listSiteAuthConnections"
|
|
118
|
+
| "getSiteAuthConnection"
|
|
119
|
+
| "createSiteAuthConnection"
|
|
120
|
+
| "updateSiteAuthConnection"
|
|
121
|
+
| "listAuthRuns"
|
|
122
|
+
| "getAuthRun"
|
|
123
|
+
| "startBrowserAuthRun"
|
|
124
|
+
| "reportBrowserAuthRun"
|
|
125
|
+
| "protectedBrowserAuthFill"
|
|
126
|
+
| "verifyBrowserAuthRun"
|
|
127
|
+
| "listInteractionInterventions"
|
|
128
|
+
| "getInteractionIntervention"
|
|
129
|
+
| "createInteractionIntervention"
|
|
130
|
+
| "resolveInteractionIntervention"
|
|
106
131
|
| "listAttachedBrowsers"
|
|
107
132
|
| "getAttachedBrowser"
|
|
108
133
|
| "listBrowserIdentities"
|
|
109
134
|
| "getBrowserIdentity"
|
|
110
135
|
| "createBrowserIdentity"
|
|
136
|
+
| "updateBrowserIdentity"
|
|
111
137
|
| "listBrowserRevisions"
|
|
112
138
|
| "listBrowserSessions"
|
|
113
139
|
| "getBrowserSession"
|
|
140
|
+
| "readBrowserClipboard"
|
|
141
|
+
| "listBrowserDownloads"
|
|
142
|
+
| "getBrowserDownload"
|
|
143
|
+
| "saveBrowserDownload"
|
|
114
144
|
| "createBrowserSession"
|
|
115
145
|
| "listBrowserTargets"
|
|
116
146
|
| "openBrowserTarget"
|
|
@@ -128,6 +158,7 @@ export type SessionClientLike = Pick<
|
|
|
128
158
|
| "endBrowserSession"
|
|
129
159
|
| "listComputerSessions"
|
|
130
160
|
| "getComputerSession"
|
|
161
|
+
| "readComputerClipboard"
|
|
131
162
|
| "createComputerSession"
|
|
132
163
|
| "listComputerTargets"
|
|
133
164
|
| "observeComputerTarget"
|
|
@@ -156,7 +187,7 @@ export type SessionClientLike = Pick<
|
|
|
156
187
|
| "terminalPtyResize"
|
|
157
188
|
| "terminalPtyClose"
|
|
158
189
|
> &
|
|
159
|
-
Partial<Pick<OpenGeniClient, "createVideoArtifactPlaybackSource">>;
|
|
190
|
+
Partial<Pick<OpenGeniClient, "createVideoArtifactPlaybackSource" | "streamWorkspaceLiveEvents">>;
|
|
160
191
|
|
|
161
192
|
/**
|
|
162
193
|
* Tenant-safe client surface required by the session-only React entry.
|
|
@@ -222,22 +253,57 @@ export type EmbeddedRealtimeSessionClientLike = Pick<
|
|
|
222
253
|
| "heartbeatSessionRealtime"
|
|
223
254
|
| "negotiateCodexRealtimeWebrtc"
|
|
224
255
|
| "negotiateGatewayRealtime"
|
|
256
|
+
| "negotiateXaiSubscriptionRealtime"
|
|
225
257
|
| "activateCodexRealtimeConnection"
|
|
226
258
|
| "syncSessionRealtimeLedger"
|
|
227
259
|
| "endSessionRealtime"
|
|
228
260
|
>;
|
|
229
261
|
|
|
262
|
+
/** Exact public SDK surface required by cross-surface human interventions. */
|
|
263
|
+
export type EmbeddedInterventionClientLike = Pick<
|
|
264
|
+
OpenGeniClient,
|
|
265
|
+
| "streamWorkspaceInteractionRevisions"
|
|
266
|
+
| "listInteractionInterventions"
|
|
267
|
+
| "getInteractionIntervention"
|
|
268
|
+
| "createInteractionIntervention"
|
|
269
|
+
| "resolveInteractionIntervention"
|
|
270
|
+
>;
|
|
271
|
+
|
|
230
272
|
/** Exact public SDK surface required by BrowserSession hooks and components. */
|
|
231
273
|
export type EmbeddedBrowserInteractionClientLike = Pick<
|
|
232
274
|
OpenGeniClient,
|
|
275
|
+
| "streamWorkspaceInteractionRevisions"
|
|
276
|
+
| "listNetworkRoutes"
|
|
277
|
+
| "getNetworkRoute"
|
|
278
|
+
| "createNetworkRoute"
|
|
279
|
+
| "updateNetworkRoute"
|
|
280
|
+
| "listSiteAuthConnections"
|
|
281
|
+
| "getSiteAuthConnection"
|
|
282
|
+
| "createSiteAuthConnection"
|
|
283
|
+
| "updateSiteAuthConnection"
|
|
284
|
+
| "listAuthRuns"
|
|
285
|
+
| "getAuthRun"
|
|
286
|
+
| "startBrowserAuthRun"
|
|
287
|
+
| "reportBrowserAuthRun"
|
|
288
|
+
| "protectedBrowserAuthFill"
|
|
289
|
+
| "verifyBrowserAuthRun"
|
|
290
|
+
| "listInteractionInterventions"
|
|
291
|
+
| "getInteractionIntervention"
|
|
292
|
+
| "createInteractionIntervention"
|
|
293
|
+
| "resolveInteractionIntervention"
|
|
233
294
|
| "listAttachedBrowsers"
|
|
234
295
|
| "getAttachedBrowser"
|
|
235
296
|
| "listBrowserIdentities"
|
|
236
297
|
| "getBrowserIdentity"
|
|
237
298
|
| "createBrowserIdentity"
|
|
299
|
+
| "updateBrowserIdentity"
|
|
238
300
|
| "listBrowserRevisions"
|
|
239
301
|
| "listBrowserSessions"
|
|
240
302
|
| "getBrowserSession"
|
|
303
|
+
| "readBrowserClipboard"
|
|
304
|
+
| "listBrowserDownloads"
|
|
305
|
+
| "getBrowserDownload"
|
|
306
|
+
| "saveBrowserDownload"
|
|
241
307
|
| "createBrowserSession"
|
|
242
308
|
| "listBrowserTargets"
|
|
243
309
|
| "openBrowserTarget"
|
|
@@ -253,13 +319,16 @@ export type EmbeddedBrowserInteractionClientLike = Pick<
|
|
|
253
319
|
| "suspendBrowserSession"
|
|
254
320
|
| "resumeBrowserSession"
|
|
255
321
|
| "endBrowserSession"
|
|
256
|
-
|
|
322
|
+
> &
|
|
323
|
+
EmbeddedInterventionClientLike;
|
|
257
324
|
|
|
258
325
|
/** Exact public SDK surface required by ComputerSession hooks and components. */
|
|
259
326
|
export type EmbeddedComputerInteractionClientLike = Pick<
|
|
260
327
|
OpenGeniClient,
|
|
328
|
+
| "streamWorkspaceInteractionRevisions"
|
|
261
329
|
| "listComputerSessions"
|
|
262
330
|
| "getComputerSession"
|
|
331
|
+
| "readComputerClipboard"
|
|
263
332
|
| "createComputerSession"
|
|
264
333
|
| "listComputerTargets"
|
|
265
334
|
| "observeComputerTarget"
|
|
@@ -268,7 +337,8 @@ export type EmbeddedComputerInteractionClientLike = Pick<
|
|
|
268
337
|
| "attachComputerSession"
|
|
269
338
|
| "heartbeatComputerSession"
|
|
270
339
|
| "endComputerSession"
|
|
271
|
-
|
|
340
|
+
> &
|
|
341
|
+
EmbeddedInterventionClientLike;
|
|
272
342
|
|
|
273
343
|
/** Complete public Browser + Computer interaction surface. */
|
|
274
344
|
export type EmbeddedInteractionClientLike = EmbeddedBrowserInteractionClientLike &
|
|
@@ -3,6 +3,11 @@ export {
|
|
|
3
3
|
type ArtifactModality,
|
|
4
4
|
type ArtifactSurfaceProps,
|
|
5
5
|
} from "./artifact-surface";
|
|
6
|
+
export {
|
|
7
|
+
PUBLISHED_HTML_ARTIFACT_IFRAME_SANDBOX,
|
|
8
|
+
PublishedHtmlArtifactFrame,
|
|
9
|
+
type PublishedHtmlArtifactFrameProps,
|
|
10
|
+
} from "./published-html-artifact-frame";
|
|
6
11
|
export {
|
|
7
12
|
SpreadsheetArtifactSurface,
|
|
8
13
|
SpreadsheetGrid,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { CSSProperties } from "react";
|
|
2
|
+
|
|
3
|
+
export const PUBLISHED_HTML_ARTIFACT_IFRAME_SANDBOX = [
|
|
4
|
+
"allow-downloads",
|
|
5
|
+
"allow-forms",
|
|
6
|
+
"allow-modals",
|
|
7
|
+
"allow-orientation-lock",
|
|
8
|
+
"allow-pointer-lock",
|
|
9
|
+
"allow-popups",
|
|
10
|
+
"allow-popups-to-escape-sandbox",
|
|
11
|
+
"allow-presentation",
|
|
12
|
+
"allow-scripts",
|
|
13
|
+
].join(" ");
|
|
14
|
+
|
|
15
|
+
export type PublishedHtmlArtifactFrameProps = {
|
|
16
|
+
html: string;
|
|
17
|
+
title: string;
|
|
18
|
+
className?: string;
|
|
19
|
+
style?: CSSProperties;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Render exact published HTML in an opaque-origin iframe. Artifact scripts,
|
|
24
|
+
* external resources, forms, popups, and downloads work without granting
|
|
25
|
+
* parent-origin authority, shared cookies/storage, or top-level navigation.
|
|
26
|
+
*/
|
|
27
|
+
export function PublishedHtmlArtifactFrame(props: PublishedHtmlArtifactFrameProps) {
|
|
28
|
+
return (
|
|
29
|
+
<iframe
|
|
30
|
+
title={props.title}
|
|
31
|
+
sandbox={PUBLISHED_HTML_ARTIFACT_IFRAME_SANDBOX}
|
|
32
|
+
referrerPolicy="no-referrer"
|
|
33
|
+
srcDoc={props.html}
|
|
34
|
+
className={props.className}
|
|
35
|
+
style={props.style}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { KeyboardEvent } from "react";
|
|
2
|
+
import { interactionHostPlatform, type InteractionHostPlatform } from "../lib/host-platform";
|
|
3
|
+
|
|
4
|
+
export const HUMAN_BROWSER_HOME_URL = "https://www.google.com/";
|
|
5
|
+
const HUMAN_BROWSER_SEARCH_URL = "https://www.google.com/search?q=";
|
|
6
|
+
|
|
7
|
+
/** Apply browser-style omnibox behavior: navigate hosts, search ordinary text. */
|
|
8
|
+
export function normalizeBrowserAddress(value: string): string | null {
|
|
9
|
+
const trimmed = value.trim();
|
|
10
|
+
if (!trimmed) return null;
|
|
11
|
+
|
|
12
|
+
if (/^(?:https?|about):/iu.test(trimmed)) {
|
|
13
|
+
try {
|
|
14
|
+
const url = new URL(trimmed);
|
|
15
|
+
return ["http:", "https:", "about:"].includes(url.protocol) ? url.href : null;
|
|
16
|
+
} catch {
|
|
17
|
+
return `${HUMAN_BROWSER_SEARCH_URL}${encodeURIComponent(trimmed)}`;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const isLocal = /^(?:localhost|127(?:\.\d{1,3}){3}|\[::1\])(?::\d+)?(?:[/?#]|$)/iu.test(trimmed);
|
|
22
|
+
const looksLikeHost =
|
|
23
|
+
!/\s/u.test(trimmed) &&
|
|
24
|
+
(isLocal || /^(?:[^./\s]+\.)+[^./\s]+(?::\d+)?(?:[/?#]|$)/u.test(trimmed));
|
|
25
|
+
if (!looksLikeHost) return `${HUMAN_BROWSER_SEARCH_URL}${encodeURIComponent(trimmed)}`;
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
return new URL(`${isLocal ? "http" : "https"}://${trimmed}`).href;
|
|
29
|
+
} catch {
|
|
30
|
+
return `${HUMAN_BROWSER_SEARCH_URL}${encodeURIComponent(trimmed)}`;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Translate executable keyboard chords for the BrowserSession action API. */
|
|
35
|
+
export function browserKey(
|
|
36
|
+
event: Pick<
|
|
37
|
+
KeyboardEvent<HTMLTextAreaElement>,
|
|
38
|
+
"altKey" | "ctrlKey" | "key" | "metaKey" | "shiftKey"
|
|
39
|
+
>,
|
|
40
|
+
hostPlatform: InteractionHostPlatform = interactionHostPlatform(),
|
|
41
|
+
): string | null {
|
|
42
|
+
// Modifier keydowns precede the actual chord key. They are not executable
|
|
43
|
+
// browser actions by themselves (for example Meta+Meta is invalid CDP input).
|
|
44
|
+
if (["Alt", "AltGraph", "Control", "Meta", "Shift"].includes(event.key)) return null;
|
|
45
|
+
const special = new Set([
|
|
46
|
+
"Enter",
|
|
47
|
+
"Tab",
|
|
48
|
+
"Escape",
|
|
49
|
+
"Backspace",
|
|
50
|
+
"Delete",
|
|
51
|
+
"ArrowUp",
|
|
52
|
+
"ArrowDown",
|
|
53
|
+
"ArrowLeft",
|
|
54
|
+
"ArrowRight",
|
|
55
|
+
]);
|
|
56
|
+
const modified = event.altKey || event.ctrlKey || event.metaKey;
|
|
57
|
+
if (!modified && !special.has(event.key)) return null;
|
|
58
|
+
const parts: string[] = [];
|
|
59
|
+
if (event.ctrlKey) parts.push(hostPlatform === "mac" ? "Control" : "Mod");
|
|
60
|
+
if (event.altKey) parts.push("Alt");
|
|
61
|
+
if (event.metaKey) parts.push(hostPlatform === "mac" ? "Mod" : "Meta");
|
|
62
|
+
if (event.shiftKey) parts.push("Shift");
|
|
63
|
+
parts.push(event.key === " " ? "Space" : event.key);
|
|
64
|
+
return parts.join("+");
|
|
65
|
+
}
|