gesso-framework 0.6.14 → 0.6.16

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/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
- import { A as output, C as equalityOf, D as input, E as InputCell, M as trackRead, N as withBodyOf, O as into, S as derive, T as internalState, _ as Resource, a as undoable, b as ComputedCell, c as classifyStorageError, d as storageReadValue, f as pick, g as mutate, h as throttled, i as OpfsStorage, j as outputTargetOf, k as isOutputTarget, l as storageErrorMessage, m as debounced, n as persisted, o as UndoStack, p as pickKeys, r as IndexedDbStorage, s as MemoryStorage, t as PersistedState, u as storageReadFailure, v as resource, w as InternalState, x as computed, y as select } from "./persisted-IXHP0d-X.js";
2
- import { A as structurallyEqual, C as applyPatches, D as channel, E as isChannelHostMessage, O as defineChannel, S as applyPatch, T as isChannelClientMessage, _ as printPropValue, a as isPortErrorMessage, b as findUnplainPath, c as servePorts, d as isConsoleEntryMessage, f as describeStream, g as formatStream, h as formatNodeReport, i as isHubMessage, k as viewKeys, l as workerHandle, m as formatNodePath, n as serveChannels, o as isPortHandshake, p as formatAge, r as APPLICATION_WORKER, s as portHandle, t as serve, u as captureConsole, v as ProvidedChannel, w as diffProjection, x as requirePlainData, y as provide } from "./serveChannels-CFzq0Hz3.js";
1
+ import { A as output, C as equalityOf, D as input, E as InputCell, M as trackRead, N as withBodyOf, O as into, S as derive, T as internalState, _ as Resource, a as undoable, b as ComputedCell, c as classifyStorageError, d as storageReadValue, f as pick, g as mutate, h as throttled, i as OpfsStorage, j as outputTargetOf, k as isOutputTarget, l as storageErrorMessage, m as debounced, n as persisted, o as UndoStack, p as pickKeys, r as IndexedDbStorage, s as MemoryStorage, t as PersistedState, u as storageReadFailure, v as resource, w as InternalState, x as computed, y as select } from "./persisted-m5v2fOju.js";
2
+ import { C as isChannelClientMessage, D as viewKeys, E as defineChannel, O as structurallyEqual, S as diffProjection, T as channel, _ as printPropValue, a as isPortErrorMessage, b as applyPatch, c as servePorts, d as isConsoleEntryMessage, f as describeStream, g as formatStream, h as formatNodeReport, i as isHubMessage, l as workerHandle, m as formatNodePath, n as serveChannels, o as isPortHandshake, p as formatAge, r as APPLICATION_WORKER, s as portHandle, t as serve, u as captureConsole, v as ProvidedChannel, w as isChannelHostMessage, x as applyPatches, y as provide } from "./serveChannels-DN2R2s0A.js";
3
3
  import { a as Each, i as show, n as getComponentMetadata, o as each, r as Show, t as createComponent } from "./createComponent-3n1ZSql8.js";
4
- import { c as channelSchema, l as describeChannel, t as AGENT_PORT } from "./remote-BEGRJ1V3.js";
5
- import { n as serveApplicationAgent } from "./app-6S4_PPB0.js";
4
+ import { c as findUnplainPath, d as describeChannel, l as requirePlainData, t as AGENT_PORT, u as channelSchema } from "./remote-CSdwpwXz.js";
5
+ import { n as serveApplicationAgent } from "./app-NLcQF2Oh.js";
6
6
  import { BehaviorSubject, EMPTY, Observable, Subject, Subscription, distinctUntilChanged, map } from "rxjs";
7
- import { AnimationDriver, Box, Canvas2DRenderer, CanvasPlatformSurface, CanvasTextMeasurer, Constraints, DefaultImageResolver, DefaultVideoResolver, DirtyFlags, EnvironmentNotifier, FocusNotifier, IconRasterizer, LayoutEngine, LayoutInspector, LayoutNotifier, MARK_PREFIX, Stack, TEXT_RUN_ID_SEPARATOR, UI_ROLES, UI_SEMANTIC_STATES, UiAnimationFrameClock, UiEditingController, UiEnvironmentKeys, UiEventType, UiFindController, UiFocusManager, UiGestureRecognizer, UiGraph, UiGraphBuilder, UiHitTester, UiHostFrameClock, UiInputDispatcher, UiInsetRegistry, UiKeyboardController, UiNodeType, UiPlatformAdapter, UiPointerController, UiPointerEvent, UiScheduler, UiSelectionController, UiSharedElements, UiSpring, UiTimerFrameClock, UiTouchScroller, UiVirtualSheet, UiVirtualWindow, UiWheelController, VIRTUAL_INDEX_PROP, VIRTUAL_LEAD_PROP, VIRTUAL_SHEET_PROP, VIRTUAL_WINDOW_PROP, WebGPURenderer, buildSemanticsSubtree, buildSemanticsTree, bumpFontStack, capturePointer, createCanvasSurface, createTween, createWebGPUSurface, defaultMotion, defineModifier, describeOverrides, diffSemantics, dragSessionFor, dropIndexShifts, easings, fade, formatExplanation, insetsEqual, isComponentLikeElement, isObservable, isWebGPUAvailable, linear, linkOf, markInstant, markNow, measure, measureSpan, motion, noInsets, observeViewportInsets, percent, performanceMarksEnabled, pointerDeviceOf, prepareInputSurface, propertyEffects, recordsEqual, registerFontStack, resolveCursor, rewalkSemantics, scrollRange, scrollbarThumb, semanticsInertAbove, semanticsMemory, setPerformanceMarks, setPerformanceMarks as setPerformanceMarks$1, textRunOfRecordId, themeTokens, touchActionFor, wheelDeltaYOf } from "gesso-core";
7
+ import { AnimationDriver, Box, Canvas2DRenderer, CanvasPlatformSurface, CanvasTextMeasurer, Constraints, DefaultImageResolver, DefaultVideoResolver, DirtyFlags, EnvironmentNotifier, FocusNotifier, IconRasterizer, LayoutEngine, LayoutInspector, LayoutNotifier, MARK_PREFIX, Stack, TEXT_RUN_ID_SEPARATOR, UI_ROLES, UI_SEMANTIC_STATES, UiAnimationFrameClock, UiEditingController, UiEnvironmentKeys, UiEventType, UiFindController, UiFocusManager, UiGestureRecognizer, UiGraph, UiGraphBuilder, UiHitTester, UiHostFrameClock, UiInputDispatcher, UiInsetRegistry, UiKeyboardController, UiNodeType, UiPlatformAdapter, UiPointerController, UiPointerEvent, UiScheduler, UiSelectionController, UiSharedElements, UiSpring, UiTimerFrameClock, UiTouchScroller, UiVirtualSheet, UiVirtualWindow, UiWheelController, VIRTUAL_INDEX_PROP, VIRTUAL_LEAD_PROP, VIRTUAL_SHEET_PROP, VIRTUAL_WINDOW_PROP, WebGPURenderer, buildSemanticsSubtree, buildSemanticsTree, bumpFontStack, capturePointer, createCanvasSurface, createTween, createWebGPUSurface, defaultMotion, defineModifier, describeOverrides, diffSemantics, dragSessionFor, dropIndexShifts, easings, fade, formatExplanation, insetsEqual, isComponentLikeElement, isImeKey, isObservable, isWebGPUAvailable, linear, linkOf, markInstant, markNow, measure, measureSpan, motion, noInsets, observeViewportInsets, percent, performanceMarksEnabled, pointerDeviceOf, prepareInputSurface, propertyEffects, recordsEqual, registerFontStack, resolveCursor, rewalkSemantics, scrollRange, scrollbarThumb, semanticsInertAbove, semanticsMemory, setPerformanceMarks, setPerformanceMarks as setPerformanceMarks$1, textRunOfRecordId, themeTokens, touchActionFor, wheelDeltaYOf } from "gesso-core";
8
8
  //#region src/Component.ts
9
9
  /**
10
10
  * Base class for all Gesso framework components.
@@ -3014,13 +3014,13 @@ var EditingProxy = class {
3014
3014
  const state = this.state;
3015
3015
  if (clipboard === null || state === null) return;
3016
3016
  event.preventDefault();
3017
- clipboard.setData("text/plain", state.text.slice(state.selectionStart, state.selectionEnd));
3017
+ clipboard.setData("text/plain", state.clipboard ?? state.text.slice(state.selectionStart, state.selectionEnd));
3018
3018
  if (state.html !== void 0) clipboard.setData("text/html", state.html);
3019
3019
  };
3020
3020
  const onCut = (event) => {
3021
3021
  const state = this.state;
3022
3022
  onCopy(event);
3023
- if (state !== null && state.selectionEnd > state.selectionStart) this.sink.beforeInput("deleteByCut", null);
3023
+ if (state !== null && (state.clipboard !== void 0 ? state.clipboard.length > 0 : state.selectionEnd > state.selectionStart)) this.sink.beforeInput("deleteByCut", null);
3024
3024
  };
3025
3025
  const onKeyDown = (event) => {
3026
3026
  this.sink.keyDown?.(event);
@@ -4155,6 +4155,41 @@ function afterLayout(run) {
4155
4155
  globalThis.requestAnimationFrame(() => globalThis.requestAnimationFrame(run));
4156
4156
  }
4157
4157
  //#endregion
4158
+ //#region src/app/pixelRatio.ts
4159
+ /**
4160
+ * Hears the window's device pixel ratio change while its size does not.
4161
+ *
4162
+ * A window dragged from a laptop's screen to an external monitor keeps
4163
+ * its size in CSS pixels, so no `ResizeObserver` fires, but each CSS
4164
+ * pixel is now a different number of device pixels. A canvas sized for
4165
+ * the old ratio is drawn blurred, or scaled, until something else
4166
+ * happens to resize it. The browser says when the ratio changes only
4167
+ * through a media query for the ratio it had, which stops matching; so
4168
+ * each change is heard once and the query is made again for the new
4169
+ * ratio.
4170
+ *
4171
+ * @returns A function that stops listening.
4172
+ */
4173
+ function watchPixelRatio(onChange, view = globalThis.window) {
4174
+ if (view === void 0 || typeof view.matchMedia !== "function") return () => {};
4175
+ let query = null;
4176
+ let stopped = false;
4177
+ const listen = () => {
4178
+ query = view.matchMedia(`(resolution: ${view.devicePixelRatio || 1}dppx)`);
4179
+ query.addEventListener("change", changed, { once: true });
4180
+ };
4181
+ function changed() {
4182
+ if (stopped) return;
4183
+ onChange(view.devicePixelRatio || 1);
4184
+ listen();
4185
+ }
4186
+ listen();
4187
+ return () => {
4188
+ stopped = true;
4189
+ query?.removeEventListener("change", changed);
4190
+ };
4191
+ }
4192
+ //#endregion
4158
4193
  //#region src/app/worker/WorkerApp.ts
4159
4194
  /**
4160
4195
  * Main-thread half of a worker-hosted Gesso application.
@@ -4195,6 +4230,35 @@ function openUrlWith(handler, url) {
4195
4230
  }
4196
4231
  window.open(url, "_blank", "noopener,noreferrer");
4197
4232
  }
4233
+ /**
4234
+ * What to say when the browser fails a worker at the worker object,
4235
+ * before the worker could say anything itself.
4236
+ *
4237
+ * Two different failures arrive this way. An exception thrown while the
4238
+ * worker's modules were evaluating is an `ErrorEvent` with a message,
4239
+ * and the message is the useful part. A script that never loaded at all
4240
+ * is a plain `Event` with no message and no filename, and the browser
4241
+ * says nothing more about it anywhere a script can read: the reason is
4242
+ * only in the network panel. That case used to be reported as "failed
4243
+ * to start: undefined", so it now says where to look and what the
4244
+ * usual reasons are. The last one is easy to hit: turn on
4245
+ * `Cross-Origin-Embedder-Policy` and a worker script the browser cached
4246
+ * before is refused, because a dev server's 304 does not repeat the
4247
+ * header.
4248
+ */
4249
+ function workerFailureMessage(worker, event) {
4250
+ const name = worker === "render" ? "the render worker" : "the app worker";
4251
+ if (hasMessage(event)) {
4252
+ const filename = event.filename;
4253
+ const where = filename === void 0 || filename === "" ? "" : ` (${filename})`;
4254
+ return `${name} failed to start: ${event.message}${where}`;
4255
+ }
4256
+ return `${name} failed to start: its script did not load. The browser's network panel has the reason; usually the file is missing (404), is served with a MIME type that is not JavaScript, or was refused under the page's Cross-Origin-Embedder-Policy (including a copy cached before the policy was turned on; a hard reload clears it).`;
4257
+ }
4258
+ function hasMessage(event) {
4259
+ const message = event.message;
4260
+ return typeof message === "string" && message !== "";
4261
+ }
4198
4262
  function resolveAppLogic(spec) {
4199
4263
  if (typeof spec === "function") return {
4200
4264
  endpoint: spec(),
@@ -4221,6 +4285,9 @@ var WorkerApp = class {
4221
4285
  canvas;
4222
4286
  host;
4223
4287
  resizeObserver = null;
4288
+ /** The host's last size, for a pixel ratio that changes on its own; see `watchPixelRatio`. */
4289
+ hostSize = null;
4290
+ stopPixelRatio = null;
4224
4291
  detachInput = null;
4225
4292
  /** Pickers and remembered handles, made on the first file request. */
4226
4293
  files = null;
@@ -4346,6 +4413,7 @@ var WorkerApp = class {
4346
4413
  this.appLogicWorker = application;
4347
4414
  this.ownsAppLogicWorker = resolved.owned;
4348
4415
  application.addEventListener("message", this.handleAppWorkerMessage);
4416
+ if (resolved.owned) application.addEventListener("error", this.handleAppWorkerFailure);
4349
4417
  application.start?.();
4350
4418
  if (this.consoleForwarding) application.postMessage({
4351
4419
  type: "gesso:console",
@@ -4424,7 +4492,7 @@ var WorkerApp = class {
4424
4492
  })
4425
4493
  }, this.proxy);
4426
4494
  const webmcp = this.options.webmcp;
4427
- if (webmcp !== void 0 && webmcp !== false) import("./webmcp-Dsp4W-pi.js").then((n) => n.a).then((agent) => agent.connectWebMcp(this, webmcp === true ? {} : webmcp)).then((disconnect) => {
4495
+ if (webmcp !== void 0 && webmcp !== false) import("./webmcp-BvQBxNjX.js").then((n) => n.a).then((agent) => agent.connectWebMcp(this, webmcp === true ? {} : webmcp)).then((disconnect) => {
4428
4496
  if (this.renderWorker === worker) this.disconnectWebMcp = disconnect;
4429
4497
  else disconnect();
4430
4498
  }, (error) => console.warn("[gesso] WebMCP could not register the channels:", error));
@@ -4450,8 +4518,22 @@ var WorkerApp = class {
4450
4518
  handleWorkerFailure = (event) => {
4451
4519
  event.preventDefault();
4452
4520
  if (this.ready) return;
4453
- const where = event.filename === void 0 || event.filename === "" ? "" : ` (${event.filename})`;
4454
- this.report(`the render worker failed to start: ${event.message}${where}`, void 0, "uncaught");
4521
+ this.report(workerFailureMessage("render", event), void 0, "uncaught");
4522
+ };
4523
+ /**
4524
+ * The app worker's counterpart, for the one failure nothing else
4525
+ * reports: a script that never loaded. Without this, an app worker
4526
+ * blocked by a 404 or by the page's embedder policy left the screen
4527
+ * waiting on channels that would never arrive, and said nothing.
4528
+ *
4529
+ * An exception inside the app worker arrives here too, with a
4530
+ * message, and is left alone: the browser reports it from inside the
4531
+ * worker with its stack, which is better than anything said here.
4532
+ */
4533
+ handleAppWorkerFailure = (event) => {
4534
+ if (hasMessage(event)) return;
4535
+ event.preventDefault();
4536
+ this.report(workerFailureMessage("app", event), void 0, "uncaught");
4455
4537
  };
4456
4538
  /** Reports an error, to `onError` or to the console it defaults to. */
4457
4539
  report(message, stack, source) {
@@ -4475,22 +4557,26 @@ var WorkerApp = class {
4475
4557
  * the first letter opens lives in exactly that gap.
4476
4558
  */
4477
4559
  forwardKeyDown(event, viaProxy = false) {
4560
+ if (isImeKey(event)) return;
4478
4561
  this.flushPendingMove();
4479
4562
  if (this.options.interceptFind === true && isFind(event) || this.options.interceptKey?.(event) === true) event.preventDefault();
4480
4563
  if (event.key === "Tab" || isSelectAll(event)) event.preventDefault();
4481
4564
  this.post({
4482
4565
  type: "keyDown",
4483
4566
  key: event.key,
4567
+ code: event.code,
4484
4568
  modifiers: modifiersFrom(event),
4485
4569
  at: epochFromEvent(event),
4486
4570
  textFollows: viaProxy
4487
4571
  });
4488
4572
  }
4489
4573
  forwardKeyUp(event) {
4574
+ if (isImeKey(event)) return;
4490
4575
  this.flushPendingMove();
4491
4576
  this.post({
4492
4577
  type: "keyUp",
4493
4578
  key: event.key,
4579
+ code: event.code,
4494
4580
  modifiers: modifiersFrom(event),
4495
4581
  at: epochFromEvent(event)
4496
4582
  });
@@ -4617,6 +4703,8 @@ var WorkerApp = class {
4617
4703
  this.audio = null;
4618
4704
  this.resizeObserver?.disconnect();
4619
4705
  this.resizeObserver = null;
4706
+ this.stopPixelRatio?.();
4707
+ this.stopPixelRatio = null;
4620
4708
  this.resizeInFlight = false;
4621
4709
  this.heldResize = null;
4622
4710
  this.canvasOrigin = null;
@@ -4629,7 +4717,10 @@ var WorkerApp = class {
4629
4717
  this.renderWorker = void 0;
4630
4718
  }
4631
4719
  this.appLogicWorker?.removeEventListener("message", this.handleAppWorkerMessage);
4632
- if (this.ownsAppLogicWorker) this.appLogicWorker?.terminate();
4720
+ if (this.ownsAppLogicWorker) {
4721
+ this.appLogicWorker?.removeEventListener("error", this.handleAppWorkerFailure);
4722
+ this.appLogicWorker?.terminate();
4723
+ }
4633
4724
  this.appLogicWorker = void 0;
4634
4725
  this.ownsAppLogicWorker = false;
4635
4726
  if (this.canvas !== void 0 && this.canvas.parentElement === this.host) this.host?.removeChild(this.canvas);
@@ -4837,13 +4928,25 @@ var WorkerApp = class {
4837
4928
  this.canvasOrigin = null;
4838
4929
  if (this.fullscreen) return;
4839
4930
  const { width, height } = entry.contentRect;
4840
- if (width > 0 && height > 0) this.requestResize({
4841
- width,
4842
- height,
4843
- dpr: window.devicePixelRatio || 1
4844
- });
4931
+ if (width > 0 && height > 0) {
4932
+ this.hostSize = {
4933
+ width,
4934
+ height
4935
+ };
4936
+ this.requestResize({
4937
+ width,
4938
+ height,
4939
+ dpr: window.devicePixelRatio || 1
4940
+ });
4941
+ }
4845
4942
  });
4846
4943
  this.resizeObserver.observe(element);
4944
+ this.stopPixelRatio = watchPixelRatio((dpr) => {
4945
+ if (this.hostSize !== null && !this.fullscreen) this.requestResize({
4946
+ ...this.hostSize,
4947
+ dpr
4948
+ });
4949
+ });
4847
4950
  }
4848
4951
  /**
4849
4952
  * Sends a size to the worker, or holds it back until the worker has
@@ -9746,7 +9849,7 @@ function timeOrigin() {
9746
9849
  }
9747
9850
  function editingStatesEqual(a, b) {
9748
9851
  if (a === null || b === null) return a === b;
9749
- return a.text === b.text && a.selectionStart === b.selectionStart && a.selectionEnd === b.selectionEnd && a.multiline === b.multiline && a.composing === b.composing && a.html === b.html && a.caret.x === b.caret.x && a.caret.y === b.caret.y && a.caret.width === b.caret.width && a.caret.height === b.caret.height;
9852
+ return a.text === b.text && a.selectionStart === b.selectionStart && a.selectionEnd === b.selectionEnd && a.multiline === b.multiline && a.composing === b.composing && a.html === b.html && a.clipboard === b.clipboard && a.caret.x === b.caret.x && a.caret.y === b.caret.y && a.caret.width === b.caret.width && a.caret.height === b.caret.height;
9750
9853
  }
9751
9854
  /** A canvas for the text measurer when the draw canvas is not a 2D one. */
9752
9855
  function createMeasureCanvas() {
@@ -9894,6 +9997,9 @@ var GessoApp = class {
9894
9997
  onOpenRoute;
9895
9998
  running = false;
9896
9999
  resizeObserver = null;
10000
+ /** The host's last size, for a pixel ratio that changes on its own; see `watchPixelRatio`. */
10001
+ hostSize = null;
10002
+ stopPixelRatio = null;
9897
10003
  proxy = null;
9898
10004
  /** The one audio element, behind `AudioService`; see `AudioSink`. */
9899
10005
  audio = null;
@@ -10134,6 +10240,8 @@ var GessoApp = class {
10134
10240
  this.adapter.detach();
10135
10241
  this.resizeObserver?.disconnect();
10136
10242
  this.resizeObserver = null;
10243
+ this.stopPixelRatio?.();
10244
+ this.stopPixelRatio = null;
10137
10245
  if (isCanvasElement(this.canvas) && this.canvas.parentElement === this.host) this.host.removeChild(this.canvas);
10138
10246
  this.runtime.dispose();
10139
10247
  }
@@ -10301,9 +10409,16 @@ var GessoApp = class {
10301
10409
  const entry = entries[0];
10302
10410
  if (entry === void 0) return;
10303
10411
  if (this.fullscreen) return;
10412
+ this.hostSize = {
10413
+ width: entry.contentRect.width,
10414
+ height: entry.contentRect.height
10415
+ };
10304
10416
  this.resize(entry.contentRect.width, entry.contentRect.height);
10305
10417
  });
10306
10418
  this.resizeObserver.observe(this.host);
10419
+ this.stopPixelRatio = watchPixelRatio(() => {
10420
+ if (this.hostSize !== null && !this.fullscreen) this.resize(this.hostSize.width, this.hostSize.height);
10421
+ });
10307
10422
  }
10308
10423
  };
10309
10424
  function createCanvasElement() {
@@ -10568,7 +10683,7 @@ var GessoAppBuilder = class {
10568
10683
  if (app === void 0 || key !== "gesso:agent") return;
10569
10684
  const pair = new MessageChannel();
10570
10685
  const registrations = this.channelRegistrations;
10571
- import("./app-6S4_PPB0.js").then((n) => n.t).then((agent) => agent.serveApplicationAgent(pair.port2, {
10686
+ import("./app-NLcQF2Oh.js").then((n) => n.t).then((agent) => agent.serveApplicationAgent(pair.port2, {
10572
10687
  channels: () => registrations.filter((registration) => registration.source !== void 0).map((registration) => ({
10573
10688
  token: registration.token,
10574
10689
  source: registration.source
@@ -10581,7 +10696,7 @@ var GessoAppBuilder = class {
10581
10696
  connectWebMcp(app) {
10582
10697
  const choice = this.webmcpChoice;
10583
10698
  if (choice === false) return;
10584
- import("./webmcp-Dsp4W-pi.js").then((n) => n.a).then((agent) => agent.connectWebMcp(this, choice === true ? {} : choice)).then((disconnect) => {
10699
+ import("./webmcp-BvQBxNjX.js").then((n) => n.a).then((agent) => agent.connectWebMcp(this, choice === true ? {} : choice)).then((disconnect) => {
10585
10700
  if (this.app === app) this.disconnectWebMcp = disconnect;
10586
10701
  else disconnect();
10587
10702
  }, (error) => console.warn("[gesso] WebMCP could not register the channels:", error));
@@ -11410,10 +11525,10 @@ var RenderWorkerApp = class {
11410
11525
  runtime.input.wheel.wheel(message.x, message.y, message.deltaX, message.deltaY, message.modifiers, message.deltaMode, message.wheelDeltaY, message.at === void 0 ? void 0 : message.at - performance.timeOrigin);
11411
11526
  break;
11412
11527
  case "keyDown":
11413
- runtime.input.keyboard.keyDown(message.key, message.modifiers, message.textFollows);
11528
+ runtime.input.keyboard.keyDown(message.key, message.modifiers, message.textFollows, message.code);
11414
11529
  break;
11415
11530
  case "keyUp":
11416
- runtime.input.keyboard.keyUp(message.key, message.modifiers);
11531
+ runtime.input.keyboard.keyUp(message.key, message.modifiers, message.code);
11417
11532
  break;
11418
11533
  case "beforeInput":
11419
11534
  runtime.input.editing.beforeInput(message.inputType, message.data);