@opengeni/react 7.1.2 → 7.2.0-canary.36239117573001

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.
Files changed (34) hide show
  1. package/dist/{browser-viewer-TZ6T76E3.js → browser-viewer-GEYFZE2W.js} +2 -2
  2. package/dist/{chunk-CP6IFD2Z.js → chunk-6IUUN2AQ.js} +124 -58
  3. package/dist/chunk-6IUUN2AQ.js.map +1 -0
  4. package/dist/{chunk-VHEY4CB3.js → chunk-RSFCYKA7.js} +5 -3
  5. package/dist/{chunk-VHEY4CB3.js.map → chunk-RSFCYKA7.js.map} +1 -1
  6. package/dist/{chunk-VI7HELBI.js → chunk-SJ5HE4ZA.js} +21 -2
  7. package/dist/chunk-SJ5HE4ZA.js.map +1 -0
  8. package/dist/{chunk-4ACTWOOW.js → chunk-VDSZ3AVO.js} +41 -18
  9. package/dist/chunk-VDSZ3AVO.js.map +1 -0
  10. package/dist/{chunk-2O2HXRGP.js → chunk-Y6DMQTLA.js} +130 -58
  11. package/dist/chunk-Y6DMQTLA.js.map +1 -0
  12. package/dist/composer.js +1 -1
  13. package/dist/{computer-viewer-FX4WOZMX.js → computer-viewer-BNHZ4PYO.js} +2 -2
  14. package/dist/index.js +5 -5
  15. package/dist/interaction.js +2 -2
  16. package/dist/session-ui.js +3 -3
  17. package/dist/session.js +1 -1
  18. package/dist/timeline/types.d.ts +2 -0
  19. package/package.json +5 -5
  20. package/src/components/browser-viewer.tsx +146 -57
  21. package/src/components/composer-transcription-control.tsx +4 -2
  22. package/src/components/composer.tsx +45 -20
  23. package/src/components/computer-viewer.tsx +161 -57
  24. package/src/hooks/use-browser-frame-stream.ts +3 -1
  25. package/src/hooks/use-voice-input.ts +12 -1
  26. package/src/timeline/compaction-copy.ts +2 -0
  27. package/src/timeline/projection.ts +31 -5
  28. package/src/timeline/types.ts +2 -0
  29. package/dist/chunk-2O2HXRGP.js.map +0 -1
  30. package/dist/chunk-4ACTWOOW.js.map +0 -1
  31. package/dist/chunk-CP6IFD2Z.js.map +0 -1
  32. package/dist/chunk-VI7HELBI.js.map +0 -1
  33. /package/dist/{browser-viewer-TZ6T76E3.js.map → browser-viewer-GEYFZE2W.js.map} +0 -0
  34. /package/dist/{computer-viewer-FX4WOZMX.js.map → computer-viewer-BNHZ4PYO.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  BrowserViewer
3
- } from "./chunk-CP6IFD2Z.js";
3
+ } from "./chunk-6IUUN2AQ.js";
4
4
  import "./chunk-TV5PP2PE.js";
5
5
  import "./chunk-5YK2ZDIG.js";
6
6
  import "./chunk-KZ73RL76.js";
@@ -11,4 +11,4 @@ import "./chunk-JVYQRRC4.js";
11
11
  export {
12
12
  BrowserViewer
13
13
  };
14
- //# sourceMappingURL=browser-viewer-TZ6T76E3.js.map
14
+ //# sourceMappingURL=browser-viewer-GEYFZE2W.js.map
@@ -56,6 +56,7 @@ import {
56
56
  useCallback as useCallback8,
57
57
  useEffect as useEffect8,
58
58
  useId,
59
+ useLayoutEffect,
59
60
  useMemo as useMemo2,
60
61
  useRef as useRef8,
61
62
  useState as useState8
@@ -74,7 +75,8 @@ var RELAY_TAG_CLOSE = 4;
74
75
  var MAX_AUTOMATIC_RECONNECTS_WITHOUT_A_FRAME = 2;
75
76
  function useBrowserFrameStream(options) {
76
77
  const { client, workspaceId } = useEmbeddedBrowserInteraction(options);
77
- const enabled = options.enabled ?? true;
78
+ const pageLive = usePageLiveActivity();
79
+ const enabled = (options.enabled ?? true) && pageLive;
78
80
  const [nonce, setNonce] = useState(0);
79
81
  const [result, setResult] = useState({
80
82
  state: "idle",
@@ -1797,6 +1799,7 @@ function BrowserViewer({
1797
1799
  const previousSessionIdRef = useRef8(sessionId);
1798
1800
  const seenInterventionIdsRef = useRef8(/* @__PURE__ */ new Set());
1799
1801
  const diagnosticRequestRef = useRef8(0);
1802
+ const viewportFocusHandoffRef = useRef8(null);
1800
1803
  const [diagnosticsView, setDiagnosticsView] = useState8(null);
1801
1804
  const notifyError = useCallback8(
1802
1805
  (cause, fallback) => {
@@ -1890,12 +1893,8 @@ function BrowserViewer({
1890
1893
  setResumeAttempt(
1891
1894
  (visible) => visible?.sessionId === selectedRegistrySession.id ? null : visible
1892
1895
  );
1893
- return;
1894
1896
  }
1895
- if (selectedRegistrySession.lifecycle === "suspended") {
1896
- void wakeBrowser(selectedRegistrySession);
1897
- }
1898
- }, [selectedRegistrySession, wakeBrowser]);
1897
+ }, [selectedRegistrySession]);
1899
1898
  const browser = useBrowserSession({
1900
1899
  ...override,
1901
1900
  browserSessionId: selection?.sessionId ?? null,
@@ -2326,6 +2325,12 @@ function BrowserViewer({
2326
2325
  /* @__PURE__ */ jsx(
2327
2326
  BrowserViewport,
2328
2327
  {
2328
+ focusHandoffRef: viewportFocusHandoffRef,
2329
+ focusScope: JSON.stringify([
2330
+ selection?.sessionId,
2331
+ browser.selectedTarget?.id,
2332
+ browser.selectedTarget?.targetGeneration
2333
+ ]),
2329
2334
  frame: displayedFrame,
2330
2335
  connectionState: displayConnectionState,
2331
2336
  supportsLiveFrames,
@@ -2350,7 +2355,14 @@ function BrowserViewer({
2350
2355
  reconnectLabel: (attachedGenerationLoss || isAttachedChromeGenerationLossError(frames.error)) && replacementChromeDevice ? "Open a fresh Connected Chrome" : void 0,
2351
2356
  reconnectMessage: attachedGenerationLoss || isAttachedChromeGenerationLossError(frames.error) ? "Chrome reconnected\u2014open a fresh browser/desktop." : void 0,
2352
2357
  onError: (cause) => notifyError(cause, "Browser input failed.")
2353
- }
2358
+ },
2359
+ JSON.stringify([
2360
+ selection?.sessionId,
2361
+ browser.selectedTarget?.id,
2362
+ browser.selectedTarget?.targetGeneration,
2363
+ browser.selectedTarget?.documentGeneration,
2364
+ frames.attachment?.controllerGeneration
2365
+ ])
2354
2366
  ),
2355
2367
  /* @__PURE__ */ jsx(
2356
2368
  BrowserStatusBar,
@@ -3073,11 +3085,24 @@ function BrowserViewport(props) {
3073
3085
  const actionTailRef = useRef8(Promise.resolve());
3074
3086
  const actionQueueEpochRef = useRef8(0);
3075
3087
  const queuedFrameRef = useRef8(null);
3088
+ const currentFrameRef = useRef8(props.frame);
3089
+ const paintedFrameRef = useRef8(null);
3090
+ const [paintedFrame, setPaintedFrame] = useState8(null);
3076
3091
  const decodingFrameRef = useRef8(false);
3077
3092
  const mountedRef = useRef8(true);
3078
3093
  actionRef.current = props.onAction;
3079
3094
  readClipboardRef.current = props.onReadClipboard;
3080
3095
  errorRef.current = props.onError;
3096
+ const clearBufferedInput = useCallback8(() => {
3097
+ if (wheelRef.current?.timer) clearTimeout(wheelRef.current.timer);
3098
+ if (pendingTextRef.current?.timer) clearTimeout(pendingTextRef.current.timer);
3099
+ wheelRef.current = null;
3100
+ pendingTextRef.current = null;
3101
+ pointerStartRef.current = null;
3102
+ lastClickRef.current = null;
3103
+ composingRef.current = false;
3104
+ if (inputRef.current) inputRef.current.value = "";
3105
+ }, []);
3081
3106
  const paintQueuedFrames = useCallback8(() => {
3082
3107
  if (decodingFrameRef.current) return;
3083
3108
  decodingFrameRef.current = true;
@@ -3096,8 +3121,10 @@ function BrowserViewport(props) {
3096
3121
  const bitmap = await createImageBitmap(blob);
3097
3122
  try {
3098
3123
  const canvas2 = canvasRef.current;
3099
- if (mountedRef.current && canvas2) {
3124
+ if (mountedRef.current && canvas2 && currentFrameRef.current && sameBrowserDocument(frame, currentFrameRef.current)) {
3100
3125
  paintCanvas(canvas2, bitmap, frame.width, frame.height);
3126
+ paintedFrameRef.current = frame;
3127
+ setPaintedFrame(frame);
3101
3128
  }
3102
3129
  } finally {
3103
3130
  bitmap.close();
@@ -3107,11 +3134,14 @@ function BrowserViewport(props) {
3107
3134
  objectUrl = URL.createObjectURL(blob);
3108
3135
  const image = await loadImage(objectUrl);
3109
3136
  const canvas = canvasRef.current;
3110
- if (mountedRef.current && canvas) {
3137
+ if (mountedRef.current && canvas && currentFrameRef.current && sameBrowserDocument(frame, currentFrameRef.current)) {
3111
3138
  paintCanvas(canvas, image, frame.width, frame.height);
3139
+ paintedFrameRef.current = frame;
3140
+ setPaintedFrame(frame);
3112
3141
  }
3113
3142
  } catch (cause) {
3114
- if (mountedRef.current) errorRef.current(cause);
3143
+ if (mountedRef.current && currentFrameRef.current && sameBrowserDocument(frame, currentFrameRef.current))
3144
+ errorRef.current(cause);
3115
3145
  } finally {
3116
3146
  if (objectUrl) URL.revokeObjectURL(objectUrl);
3117
3147
  }
@@ -3122,38 +3152,56 @@ function BrowserViewport(props) {
3122
3152
  }
3123
3153
  })();
3124
3154
  }, []);
3125
- useEffect8(() => {
3155
+ useLayoutEffect(() => {
3156
+ const keyboardInput = inputRef.current;
3157
+ const focusHandoff = props.focusHandoffRef;
3126
3158
  mountedRef.current = true;
3159
+ if (focusHandoff.current === props.focusScope) {
3160
+ keyboardInput?.focus({ preventScroll: true });
3161
+ }
3162
+ focusHandoff.current = null;
3127
3163
  return () => {
3164
+ if (document.activeElement === keyboardInput) {
3165
+ focusHandoff.current = props.focusScope;
3166
+ }
3128
3167
  mountedRef.current = false;
3168
+ actionQueueEpochRef.current += 1;
3129
3169
  queuedFrameRef.current = null;
3170
+ clearBufferedInput();
3130
3171
  };
3131
- }, []);
3132
- useEffect8(() => {
3133
- if (!props.frame) return;
3172
+ }, [clearBufferedInput, props.focusHandoffRef, props.focusScope]);
3173
+ useLayoutEffect(() => {
3174
+ if (currentFrameRef.current && !props.frame) {
3175
+ actionQueueEpochRef.current += 1;
3176
+ clearBufferedInput();
3177
+ }
3178
+ currentFrameRef.current = props.frame;
3179
+ if (!props.frame) {
3180
+ queuedFrameRef.current = null;
3181
+ paintedFrameRef.current = null;
3182
+ setPaintedFrame(null);
3183
+ return;
3184
+ }
3134
3185
  queuedFrameRef.current = props.frame;
3135
3186
  paintQueuedFrames();
3136
- }, [paintQueuedFrames, props.frame]);
3137
- useEffect8(
3138
- () => () => {
3139
- if (wheelRef.current?.timer) clearTimeout(wheelRef.current.timer);
3140
- if (pendingTextRef.current?.timer) clearTimeout(pendingTextRef.current.timer);
3141
- },
3142
- []
3143
- );
3187
+ }, [clearBufferedInput, paintQueuedFrames, props.frame]);
3144
3188
  const enqueue = useCallback8(
3145
3189
  (action, frame, after) => {
3146
3190
  const epoch = actionQueueEpochRef.current;
3191
+ const dispatch = actionRef.current;
3147
3192
  actionTailRef.current = actionTailRef.current.catch(() => void 0).then(async () => {
3148
- if (epoch !== actionQueueEpochRef.current) return;
3149
- const receipt = await actionRef.current(action, frame);
3193
+ if (!mountedRef.current || epoch !== actionQueueEpochRef.current) return;
3194
+ const receipt = await dispatch(action, frame);
3195
+ if (!mountedRef.current || epoch !== actionQueueEpochRef.current) return;
3150
3196
  await after?.(receipt);
3151
3197
  }).catch((cause) => {
3198
+ if (!mountedRef.current || epoch !== actionQueueEpochRef.current) return;
3152
3199
  actionQueueEpochRef.current += 1;
3200
+ clearBufferedInput();
3153
3201
  errorRef.current(cause);
3154
3202
  });
3155
3203
  },
3156
- []
3204
+ [clearBufferedInput]
3157
3205
  );
3158
3206
  const point = useCallback8(
3159
3207
  (frame, clientX, clientY) => browserPoint(canvasRef.current, frame, clientX, clientY),
@@ -3169,15 +3217,34 @@ function BrowserViewport(props) {
3169
3217
  const flushPendingClick = useCallback8(() => {
3170
3218
  lastClickRef.current = null;
3171
3219
  }, []);
3220
+ const flushPendingWheel = useCallback8(() => {
3221
+ const batch = wheelRef.current;
3222
+ if (!batch) return;
3223
+ if (batch.timer) clearTimeout(batch.timer);
3224
+ wheelRef.current = null;
3225
+ enqueue(
3226
+ {
3227
+ type: "pointer",
3228
+ action: "scroll",
3229
+ x: batch.x,
3230
+ y: batch.y,
3231
+ deltaX: batch.deltaX,
3232
+ deltaY: batch.deltaY
3233
+ },
3234
+ batch.frame
3235
+ );
3236
+ }, [enqueue]);
3172
3237
  const pointerDown = (event) => {
3173
- if (!props.frame || event.button !== 0) return;
3238
+ const frame = paintedFrameRef.current;
3239
+ if (!frame || event.button !== 0) return;
3174
3240
  event.preventDefault();
3241
+ flushPendingWheel();
3175
3242
  flushPendingText();
3176
3243
  pointerStartRef.current = {
3177
3244
  x: event.clientX,
3178
3245
  y: event.clientY,
3179
3246
  pointerId: event.pointerId,
3180
- frame: props.frame
3247
+ frame
3181
3248
  };
3182
3249
  event.currentTarget.setPointerCapture?.(event.pointerId);
3183
3250
  inputRef.current?.focus({ preventScroll: true });
@@ -3216,48 +3283,39 @@ function BrowserViewport(props) {
3216
3283
  };
3217
3284
  const contextMenu = (event) => {
3218
3285
  event.preventDefault();
3219
- const frame = props.frame;
3286
+ const frame = paintedFrameRef.current;
3220
3287
  if (!frame) return;
3288
+ flushPendingWheel();
3221
3289
  flushPendingText();
3222
3290
  flushPendingClick();
3223
3291
  const at = point(frame, event.clientX, event.clientY);
3224
3292
  if (at) enqueue({ type: "pointer", action: "click", x: at.x, y: at.y, button: "right" }, frame);
3225
3293
  };
3226
3294
  const wheel = (event) => {
3227
- const frame = props.frame;
3295
+ const frame = paintedFrameRef.current;
3228
3296
  if (!frame) return;
3229
3297
  const at = point(frame, event.clientX, event.clientY);
3230
3298
  if (!at) return;
3231
3299
  flushPendingText();
3232
3300
  flushPendingClick();
3233
3301
  event.preventDefault();
3234
- const pending = wheelRef.current;
3235
- if (pending?.timer) clearTimeout(pending.timer);
3302
+ let pending = wheelRef.current;
3303
+ if (pending && (!sameBrowserDocument(pending.frame, frame) || Math.hypot(pending.x - at.x, pending.y - at.y) > 6)) {
3304
+ flushPendingWheel();
3305
+ pending = null;
3306
+ }
3236
3307
  wheelRef.current = {
3237
3308
  x: at.x,
3238
3309
  y: at.y,
3239
- deltaX: (pending && sameFrameFence(pending.frame, frame) ? pending.deltaX : 0) + event.deltaX,
3240
- deltaY: (pending && sameFrameFence(pending.frame, frame) ? pending.deltaY : 0) + event.deltaY,
3310
+ deltaX: (pending?.deltaX ?? 0) + event.deltaX,
3311
+ deltaY: (pending?.deltaY ?? 0) + event.deltaY,
3241
3312
  frame,
3242
- timer: setTimeout(() => {
3243
- const batch = wheelRef.current;
3244
- wheelRef.current = null;
3245
- if (batch)
3246
- enqueue(
3247
- {
3248
- type: "pointer",
3249
- action: "scroll",
3250
- x: batch.x,
3251
- y: batch.y,
3252
- deltaX: batch.deltaX,
3253
- deltaY: batch.deltaY
3254
- },
3255
- batch.frame
3256
- );
3257
- }, 45)
3313
+ // Retain the first event's deadline so a continuous gesture keeps moving.
3314
+ timer: pending?.timer ?? setTimeout(flushPendingWheel, 45)
3258
3315
  };
3259
3316
  };
3260
3317
  const keyDown = (event) => {
3318
+ flushPendingWheel();
3261
3319
  const command = event.metaKey || event.ctrlKey;
3262
3320
  if (props.clipboardEnabled && command && !event.altKey && ["c", "v"].includes(event.key.toLowerCase())) {
3263
3321
  flushPendingText();
@@ -3268,15 +3326,18 @@ function BrowserViewport(props) {
3268
3326
  event.preventDefault();
3269
3327
  flushPendingText();
3270
3328
  flushPendingClick();
3271
- enqueue({ type: "press", key }, props.frame);
3329
+ enqueue({ type: "press", key }, paintedFrameRef.current);
3272
3330
  };
3273
3331
  const copy = (event) => {
3274
3332
  if (!props.clipboardEnabled) return;
3275
3333
  event.preventDefault();
3334
+ flushPendingWheel();
3276
3335
  flushPendingText();
3277
3336
  flushPendingClick();
3278
- enqueue({ type: "clipboard", operation: "copy" }, props.frame, async () => {
3279
- const clipboard = await readClipboardRef.current();
3337
+ const readClipboard = readClipboardRef.current;
3338
+ enqueue({ type: "clipboard", operation: "copy" }, paintedFrameRef.current, async () => {
3339
+ const clipboard = await readClipboard();
3340
+ if (!mountedRef.current) return;
3280
3341
  if (clipboard.text.length === 0) return;
3281
3342
  if (!await copyTextToClipboard(clipboard.text)) {
3282
3343
  throw new Error("Browser text could not be copied to the local clipboard");
@@ -3286,6 +3347,7 @@ function BrowserViewport(props) {
3286
3347
  const paste = (event) => {
3287
3348
  if (!props.clipboardEnabled) return;
3288
3349
  event.preventDefault();
3350
+ flushPendingWheel();
3289
3351
  flushPendingText();
3290
3352
  flushPendingClick();
3291
3353
  enqueue(
@@ -3294,15 +3356,16 @@ function BrowserViewport(props) {
3294
3356
  operation: "paste",
3295
3357
  text: event.clipboardData.getData("text/plain")
3296
3358
  },
3297
- props.frame
3359
+ paintedFrameRef.current
3298
3360
  );
3299
3361
  };
3300
3362
  const input = (value, nativeComposing = false) => {
3301
3363
  if (composingRef.current || nativeComposing) return;
3302
3364
  if (!value) return;
3365
+ flushPendingWheel();
3303
3366
  flushPendingClick();
3304
3367
  const pending = pendingTextRef.current;
3305
- if (pending && sameOptionalBrowserFrame(pending.frame, props.frame)) {
3368
+ if (pending && sameOptionalBrowserFrame(pending.frame, paintedFrameRef.current)) {
3306
3369
  clearTimeout(pending.timer);
3307
3370
  pending.text += value;
3308
3371
  pending.timer = setTimeout(flushPendingText, 16);
@@ -3310,7 +3373,7 @@ function BrowserViewport(props) {
3310
3373
  flushPendingText();
3311
3374
  pendingTextRef.current = {
3312
3375
  text: value,
3313
- frame: props.frame,
3376
+ frame: paintedFrameRef.current,
3314
3377
  timer: setTimeout(flushPendingText, 16)
3315
3378
  };
3316
3379
  }
@@ -3323,7 +3386,7 @@ function BrowserViewport(props) {
3323
3386
  composingRef.current = false;
3324
3387
  input(event.currentTarget.value || event.data);
3325
3388
  };
3326
- const showCanvas = props.frame !== null;
3389
+ const showCanvas = props.frame !== null && paintedFrame !== null && sameBrowserDocument(props.frame, paintedFrame);
3327
3390
  return /* @__PURE__ */ jsxs("div", { className: "relative min-h-0 flex-1 overflow-hidden bg-black", children: [
3328
3391
  /* @__PURE__ */ jsx(
3329
3392
  "canvas",
@@ -3893,7 +3956,10 @@ function frameMatchesSelectedTarget(frame, session, target) {
3893
3956
  );
3894
3957
  }
3895
3958
  function sameFrameFence(left, right) {
3896
- return left.browserSessionId === right.browserSessionId && left.controllerGeneration === right.controllerGeneration && left.targetId === right.targetId && left.targetGeneration === right.targetGeneration && left.documentGeneration === right.documentGeneration && left.frameId === right.frameId;
3959
+ return sameBrowserDocument(left, right) && left.frameId === right.frameId;
3960
+ }
3961
+ function sameBrowserDocument(left, right) {
3962
+ return left.browserSessionId === right.browserSessionId && left.controllerGeneration === right.controllerGeneration && left.targetId === right.targetId && left.targetGeneration === right.targetGeneration && left.documentGeneration === right.documentGeneration;
3897
3963
  }
3898
3964
  function sameOptionalBrowserFrame(left, right) {
3899
3965
  return left === null || right === null ? left === right : sameFrameFence(left, right);
@@ -3978,4 +4044,4 @@ export {
3978
4044
  useBrowserFrameStream,
3979
4045
  BrowserViewer
3980
4046
  };
3981
- //# sourceMappingURL=chunk-CP6IFD2Z.js.map
4047
+ //# sourceMappingURL=chunk-6IUUN2AQ.js.map