buninu-browser 0.7.0 → 0.9.1

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 (142) hide show
  1. package/AGENTS.md +5 -0
  2. package/README.md +90 -1
  3. package/buninu-browser.js +1 -1
  4. package/frontends/wayland/README.md +35 -2
  5. package/frontends/wayland/client.js +8 -6
  6. package/frontends/wayland/clipboard.js +1 -1
  7. package/frontends/wayland/index.js +1 -1
  8. package/frontends/wayland/input.js +1 -1
  9. package/frontends/wayland/resource-io.js +6 -0
  10. package/frontends/wayland/transport-posix.js +120 -0
  11. package/frontends/wayland/transport-win32.js +9 -0
  12. package/frontends/wayland/transport.js +3 -120
  13. package/frontends/wayland/win32-resources.js +80 -0
  14. package/frontends/wayland/win32-wire.js +62 -0
  15. package/lib/audio/biquad.js +25 -0
  16. package/lib/audio/piano.js +6 -3
  17. package/lib/audio/playback-buffer.js +5 -5
  18. package/lib/audio/pulse-client.js +24 -5
  19. package/lib/audio/web-audio.js +570 -0
  20. package/lib/browser-dialog.js +126 -0
  21. package/lib/cdp-server.js +43 -11
  22. package/lib/file-picker.js +48 -0
  23. package/lib/headless-shell.js +34 -12
  24. package/lib/layout/text-layout.js +112 -19
  25. package/lib/media/mp4-frame-times.js +93 -0
  26. package/lib/paint/direct-canvas.ts +39 -0
  27. package/lib/paint/display-list.js +37 -12
  28. package/lib/paint/raster-readback.js +16 -7
  29. package/lib/renderer/animation-frames.js +10 -5
  30. package/lib/renderer/bindings.js +69 -16
  31. package/lib/renderer/canvas-2d.js +265 -15
  32. package/lib/renderer/canvas-round-rect.js +36 -0
  33. package/lib/renderer/css-animations.js +173 -0
  34. package/lib/renderer/dialog-client.js +30 -0
  35. package/lib/renderer/dialog-worker.js +35 -0
  36. package/lib/renderer/eval-environment.js +28 -0
  37. package/lib/renderer/file-input.js +49 -0
  38. package/lib/renderer/host.js +33 -4
  39. package/lib/renderer/html-drag.js +77 -0
  40. package/lib/renderer/image-loading.js +45 -2
  41. package/lib/renderer/main.js +4 -0
  42. package/lib/renderer/module-transform.js +5 -3
  43. package/lib/renderer/page-builtins.js +59 -0
  44. package/lib/renderer/page-realm.js +177 -40
  45. package/lib/renderer/page-renderer.js +397 -49
  46. package/lib/renderer/piano-input.js +3 -1
  47. package/lib/renderer/raster-surface.js +18 -0
  48. package/lib/renderer/script-rewrite.js +165 -9
  49. package/lib/renderer/video-presentation.js +5 -4
  50. package/lib/renderer/webgl/clip.js +24 -0
  51. package/lib/renderer/webgl/context.js +158 -0
  52. package/lib/renderer/webgl/cpu-fragment.js +211 -0
  53. package/lib/renderer/webgl/draw-cache.js +22 -0
  54. package/lib/renderer/webgl/pipeline.js +70 -0
  55. package/lib/renderer/webgl/shaders.js +58 -0
  56. package/lib/renderer/webgl/textures.js +43 -0
  57. package/lib/renderer/window-named-properties.js +46 -0
  58. package/lib/screenshot-cli.js +4 -7
  59. package/lib/style/animation-values.js +29 -0
  60. package/lib/style/computed-style.js +109 -13
  61. package/lib/style/transform.js +44 -0
  62. package/lib/window-size.js +10 -0
  63. package/package.json +1 -1
  64. package/patches/happy-dom/0007-scope-content-models-to-html-namespace.patch +29 -0
  65. package/patches/happy-dom/README.md +16 -0
  66. package/test/animation-frames.test.js +15 -0
  67. package/test/canvas-2d.test.js +252 -4
  68. package/test/canvas-frame-pacing.test.js +7 -0
  69. package/test/cdp-viewers.test.js +36 -0
  70. package/test/classic-games-patches/0001-fix-game-initialization.patch +177 -0
  71. package/test/classic-games-patches/README.md +156 -0
  72. package/test/classic-games-scenarios.js +133 -0
  73. package/test/clipboard.test.js +16 -0
  74. package/test/computed-style.test.js +18 -0
  75. package/test/css-animation-lifecycle.test.js +28 -0
  76. package/test/css-animations.test.js +83 -0
  77. package/test/direct-canvas.test.js +39 -0
  78. package/test/dynamic-inline-handlers.test.js +25 -0
  79. package/test/eval-declarations.test.js +22 -0
  80. package/test/file-picker.test.js +34 -0
  81. package/test/fixtures/canvas-damage.js +23 -0
  82. package/test/fixtures/canvas-frame-pacing.js +35 -0
  83. package/test/fixtures/direct-canvas.js +96 -0
  84. package/test/fixtures/javascript-dialogs.html +8 -0
  85. package/test/fixtures/media-audio-lifetime.js +65 -0
  86. package/test/fixtures/renderer-memory.js +7 -5
  87. package/test/fixtures/video-black-replay.js +8 -6
  88. package/test/fixtures/video-slow-end.js +39 -0
  89. package/test/fixtures/web-audio-renderer.js +45 -0
  90. package/test/flex.test.js +26 -0
  91. package/test/grid.test.js +13 -0
  92. package/test/headless-shell.test.js +9 -0
  93. package/test/headless-window-size.test.js +28 -0
  94. package/test/html-rcdata.test.js +35 -0
  95. package/test/image-decode.test.js +18 -0
  96. package/test/javascript-dialog.test.js +83 -0
  97. package/test/manual-breakout-paddle.js +42 -0
  98. package/test/manual-breakout-static.js +35 -0
  99. package/test/manual-classic-games.js +41 -0
  100. package/test/manual-clumsy-bird-three-pipes.js +81 -0
  101. package/test/manual-clumsy-bird.js +52 -0
  102. package/test/manual-hextris.js +30 -0
  103. package/test/manual-numbered-music.js +24 -0
  104. package/test/manual-t-rex-runner.js +49 -0
  105. package/test/manual-threejs-scene.js +64 -0
  106. package/test/manual-webgl-benchmark.js +27 -0
  107. package/test/manual-webgl-cpu.html +26 -0
  108. package/test/media-audio-lifetime.test.js +8 -0
  109. package/test/mp4-frame-times.test.js +33 -0
  110. package/test/page-scripts.test.js +96 -1
  111. package/test/piano-input.test.js +15 -2
  112. package/test/piano.test.js +11 -2
  113. package/test/playback-buffer.test.js +11 -0
  114. package/test/pointer-drag.test.js +33 -0
  115. package/test/positioning.test.js +82 -0
  116. package/test/pulse-client.test.js +51 -2
  117. package/test/raster-readback.test.js +14 -0
  118. package/test/script-rewrite.test.js +61 -3
  119. package/test/video-slow-end.test.js +6 -0
  120. package/test/viewport-keyboard-overflow.test.js +25 -0
  121. package/test/wayland-win32-resources.test.js +47 -0
  122. package/test/wayland-win32-wire.test.js +59 -0
  123. package/test/web-audio-renderer.test.js +8 -0
  124. package/test/web-audio.test.js +264 -0
  125. package/test/webgl-clip.test.js +9 -0
  126. package/test/webgl-cpu-fragment.test.js +43 -0
  127. package/test/window-named-properties.test.js +41 -0
  128. package/vendor/happy-dom/packages/happy-dom/src/config/HTMLElementConfig.ts +2 -2
  129. package/vendor/happy-dom/packages/happy-dom/src/config/HTMLElementConfigContentModelEnum.ts +1 -0
  130. package/vendor/happy-dom/packages/happy-dom/src/html-parser/HTMLParser.ts +23 -3
  131. package/vendor/happy-dom/packages/happy-dom/src/query-selector/SelectorParser.ts +1 -1
  132. package/vendor/land-renderer/LICENSE +21 -0
  133. package/vendor/land-renderer/README.md +14 -0
  134. package/vendor/land-renderer/direct-compositor.ts +443 -0
  135. package/vendor/land-renderer/frame.js +88 -0
  136. package/vendor/land-renderer/png-fast.js +85 -0
  137. package/vendor/land-renderer/raw-frames.js +66 -0
  138. package/vendor/land-renderer/render-types.ts +7 -0
  139. package/vendor/land-renderer/renderer.ts +134 -0
  140. package/vendor/land-renderer/snapshot.js +37 -0
  141. package/vendor/land-renderer/viewport.js +18 -0
  142. package/vendor/ses/dist/ses.mjs +1 -1
@@ -1,3 +1,6 @@
1
+ import {animationProperty} from '../style/animation-values.js';
2
+ import {inputFiles} from './file-input.js';
3
+ import { DataTransfer, dragData, dragEvent, isDraggable } from './html-drag.js';
1
4
  /**
2
5
  * DOM bindings: the only view page scripts get of the document.
3
6
  *
@@ -227,7 +230,7 @@ export class BindingRealm {
227
230
  if (!wrapper) {
228
231
  wrapper = new EventBinding(CONSTRUCT, event, this, detail);
229
232
  if (this.eventPrototype) {
230
- const prototype = this.eventPrototypes?.get(this.#messages.has(event) ? "MessageEvent" : event.constructor?.name) ?? this.eventPrototype;
233
+ const prototype = this.eventPrototypes?.get(this.#messages.has(event) ? "MessageEvent" : dragData(event) !== undefined ? "DragEvent" : event.constructor?.name) ?? this.eventPrototype;
231
234
  Object.setPrototypeOf(wrapper, prototype);
232
235
  // isTrusted is [LegacyUnforgeable]: an own accessor of every event.
233
236
  const isTrusted = Object.getOwnPropertyDescriptor(EventBinding.prototype, "isTrusted");
@@ -525,6 +528,7 @@ class NodeBinding {
525
528
  dispatchEvent(event) {
526
529
  const real = EventBinding.unwrap(event);
527
530
  if (!real) throw new TypeError("dispatchEvent requires an Event");
531
+ this.#realm.hooks.prepareEvent?.(this.#node, real.type);
528
532
  return this.#node.dispatchEvent(real);
529
533
  }
530
534
  }
@@ -821,7 +825,11 @@ class ElementBinding extends ParentBinding {
821
825
  }
822
826
 
823
827
  get classList() {
824
- this.#classList ??= new ClassListBinding(CONSTRUCT, nodeOf(this), realmOf(this));
828
+ if (!this.#classList) {
829
+ const realm=realmOf(this);
830
+ this.#classList=new ClassListBinding(CONSTRUCT,nodeOf(this),realm);
831
+ if(realm.tokenListPrototype)Object.setPrototypeOf(this.#classList,realm.tokenListPrototype);
832
+ }
825
833
  return this.#classList;
826
834
  }
827
835
 
@@ -1061,6 +1069,8 @@ class ElementBinding extends ParentBinding {
1061
1069
  inserted(this, list);
1062
1070
  }
1063
1071
 
1072
+ get files(){return inputFiles(nodeOf(this));}
1073
+ showPicker(){const e=nodeOf(this);if(e.disabled)throw new DOMException('The input is disabled','InvalidStateError');realmOf(this).hooks.pickFile?.(e);}
1064
1074
  click() {
1065
1075
  const realm = realmOf(this);
1066
1076
  const element = nodeOf(this);
@@ -1072,6 +1082,7 @@ class ElementBinding extends ParentBinding {
1072
1082
  this.#clickInProgress = true;
1073
1083
  try {
1074
1084
  element.dispatchEvent(event);
1085
+ if (!event.defaultPrevented) realm.hooks.pickFile?.(element);
1075
1086
  if (!event.defaultPrevented && anchor?.hasAttribute("href")) realm.hooks.activateLink?.(anchor);
1076
1087
  } finally {
1077
1088
  this.#clickInProgress = false;
@@ -1112,7 +1123,7 @@ class ElementBinding extends ParentBinding {
1112
1123
  if(!arguments.length)throw new TypeError('setRangeText requires replacement');
1113
1124
  nodeOf(this).setRangeText(String(replacement),...args.map((v,i)=>i<2?Number(v):String(v)));touch(this);
1114
1125
  }
1115
- select() {nodeOf(this).select();touch(this);}
1126
+ select() {const node=nodeOf(this);node.focus();node.select();touch(this);}
1116
1127
 
1117
1128
  setCustomValidity(message) {
1118
1129
  if (!arguments.length) throw new TypeError("setCustomValidity requires a message");
@@ -1137,6 +1148,9 @@ class ElementBinding extends ParentBinding {
1137
1148
  if (node.ownerDocument.activeElement !== previous) touch(this, [":focus", ":focus-visible"]);
1138
1149
  }
1139
1150
 
1151
+ get draggable() { return isDraggable(nodeOf(this)); }
1152
+ set draggable(value) { nodeOf(this).setAttribute('draggable',Boolean(value) ? 'true' : 'false'); touch(this); }
1153
+
1140
1154
  getBoundingClientRect() {
1141
1155
  const rect = realmOf(this).hooks.boundsOf(nodeOf(this)) ?? { left: 0, top: 0, width: 0, height: 0 };
1142
1156
  return domRect(rect);
@@ -1378,6 +1392,7 @@ function isMedia(wrapper) {
1378
1392
 
1379
1393
  /** on* event handler properties (element.onclick = fn, script.onload = fn). */
1380
1394
  export const EVENT_HANDLER_NAMES = Object.freeze([
1395
+ "dragstart", "drag", "dragenter", "dragleave", "dragover", "drop", "dragend", "pointercancel",
1381
1396
  "click", "auxclick", "dblclick", "mousedown", "mouseup", "mousemove", "mouseover", "mouseout", "mouseenter", "mouseleave",
1382
1397
  "keydown", "keyup", "keypress", "beforeinput", "input", "change", "submit", "reset", "focus", "blur", "load", "error",
1383
1398
  "abort", "scroll", "resize", "wheel", "contextmenu", "touchstart", "touchend", "touchmove",
@@ -1394,11 +1409,13 @@ export function defineEventHandlerProperty(object, type, targetOf, realmFor) {
1394
1409
  configurable: true,
1395
1410
  enumerable: true,
1396
1411
  get() {
1412
+ realmFor(this).hooks.prepareHandler?.(targetOf(this), type);
1397
1413
  return handlers.get(this)?.handler ?? null;
1398
1414
  },
1399
1415
  set(value) {
1400
1416
  const realm = realmFor(this);
1401
1417
  const target = targetOf(this);
1418
+ realm.hooks.prepareHandler?.(target, type);
1402
1419
  const previous = handlers.get(this);
1403
1420
  if (previous) target.removeEventListener(type, previous.listener);
1404
1421
  handlers.delete(this);
@@ -1427,6 +1444,10 @@ for (const property of REFLECTED_PROPERTIES) {
1427
1444
  get() {
1428
1445
  const node = nodeOf(this);
1429
1446
  const value = node[property];
1447
+ if (property === "value" && node.tagName === "INPUT" && node.type === "file") {
1448
+ const file = inputFiles(node)[0];
1449
+ return file ? "C:\\fakepath\\" + file.name : "";
1450
+ }
1430
1451
  if (typeof value === "string" && ["src", "href", "action", "poster"].includes(property)) {
1431
1452
  const attribute = node.getAttribute(property);
1432
1453
  if (property === "action" && !attribute) return node.ownerDocument.URL;
@@ -1531,6 +1552,15 @@ class DocumentBinding extends ParentBinding {
1531
1552
  return realm.wrap(node === realm.window.document && realm.hooks.body ? realm.hooks.body() : node.body);
1532
1553
  }
1533
1554
 
1555
+ execCommand(command, _showUI = false, _value = null) {
1556
+ return Boolean(realmOf(this).hooks.execCommand?.(String(command).toLowerCase()));
1557
+ }
1558
+
1559
+ queryCommandSupported(command) { return String(command).toLowerCase() === 'copy'; }
1560
+ queryCommandEnabled(command) {
1561
+ return this.queryCommandSupported(command) && Boolean(realmOf(this).hooks.copyEnabled?.());
1562
+ }
1563
+
1534
1564
  get title() {
1535
1565
  return nodeOf(this).title;
1536
1566
  }
@@ -1853,11 +1883,15 @@ class EventBinding {
1853
1883
  }
1854
1884
 
1855
1885
  get offsetX() {
1856
- return this.#event.offsetX ?? 0;
1886
+ // CSSOM View: relative to the target padding edge while dispatching;
1887
+ // outside dispatch offsetX/Y fall back to pageX/Y (also for synthetic events).
1888
+ if (!this.#event.eventPhase) return this.pageX;
1889
+ return this.#realm.hooks.mouseOffset?.(this.#event.target, this.clientX, this.clientY)?.x ?? this.pageX;
1857
1890
  }
1858
1891
 
1859
1892
  get offsetY() {
1860
- return this.#event.offsetY ?? 0;
1893
+ if (!this.#event.eventPhase) return this.pageY;
1894
+ return this.#realm.hooks.mouseOffset?.(this.#event.target, this.clientX, this.clientY)?.y ?? this.pageY;
1861
1895
  }
1862
1896
 
1863
1897
  get movementX() {
@@ -1868,6 +1902,8 @@ class EventBinding {
1868
1902
  return this.#event.movementY ?? 0;
1869
1903
  }
1870
1904
 
1905
+ get dataTransfer() { return dragData(this.#event) ?? null; }
1906
+
1871
1907
  get relatedTarget() {
1872
1908
  return this.#realm.wrap(this.#event.relatedTarget ?? null) ?? null;
1873
1909
  }
@@ -1918,6 +1954,10 @@ class EventBinding {
1918
1954
  return typeof this.#event.newURL === "string" ? this.#event.newURL : undefined;
1919
1955
  }
1920
1956
 
1957
+ get animationName() { return this.#event.animationName ?? ""; }
1958
+ get elapsedTime() { return this.#event.elapsedTime ?? 0; }
1959
+ get pseudoElement() { return this.#event.pseudoElement ?? ""; }
1960
+
1921
1961
  get key() {
1922
1962
  return this.#event.key;
1923
1963
  }
@@ -2409,17 +2449,17 @@ export function cssStyleDeclarationInterface(realm) {
2409
2449
  get cssFloat() { return styleState(this).style.getPropertyValue("float"); },
2410
2450
  set cssFloat(value) { this.setProperty("float", value); },
2411
2451
  item(index) { return styleState(this).style.item?.(Number(index) >>> 0) ?? ""; },
2412
- getPropertyValue(property) { return styleState(this).style.getPropertyValue(String(property)); },
2413
- getPropertyPriority(property) { return styleState(this).style.getPropertyPriority?.(String(property)) ?? ""; },
2452
+ getPropertyValue(property) { return styleState(this).style.getPropertyValue(animationProperty(property)); },
2453
+ getPropertyPriority(property) { return styleState(this).style.getPropertyPriority?.(animationProperty(property)) ?? ""; },
2414
2454
  setProperty(property, value, priority = "") {
2415
2455
  const { style, node, realm: owner } = styleState(this);
2416
2456
  const before = style.cssText;
2417
- style.setProperty(String(property), value === null ? "" : String(value), String(priority));
2457
+ style.setProperty(animationProperty(property), value === null ? "" : String(value), String(priority));
2418
2458
  if (style.cssText !== before) owner.hooks.touch(node);
2419
2459
  },
2420
2460
  removeProperty(property) {
2421
2461
  const { style, node, realm: owner } = styleState(this);
2422
- const previous = style.removeProperty(String(property));
2462
+ const previous = style.removeProperty(animationProperty(property));
2423
2463
  owner.hooks.touch(node);
2424
2464
  return previous;
2425
2465
  },
@@ -2443,8 +2483,7 @@ export function cssStyleDeclarationInterface(realm) {
2443
2483
  function styleBinding(node, realm) {
2444
2484
  const style = node.style;
2445
2485
  const prototype = cssStyleDeclarationInterface(realm).prototype;
2446
- const toKebab = (property) => property.startsWith("--") ? property
2447
- : property.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
2486
+ const toKebab = (property) => property.startsWith("--") ? property : animationProperty(property);
2448
2487
  const proxy = new Proxy(Object.create(prototype), {
2449
2488
  get(target, property, receiver) {
2450
2489
  if (typeof property !== "string" || property in prototype) return Reflect.get(target, property, receiver);
@@ -2460,6 +2499,8 @@ function styleBinding(node, realm) {
2460
2499
  },
2461
2500
  has: (_target, property) => {
2462
2501
  if (typeof property !== "string") return property in prototype;
2502
+ const normalized = animationProperty(property);
2503
+ if(/^animation(?:-(?:name|duration|delay|iteration-count|direction|fill-mode|play-state|timing-function))?$/.test(normalized))return normalized in style || normalized.replace(/-([a-z])/g, (_,letter)=>letter.toUpperCase()) in style;
2463
2504
  const camel = property.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
2464
2505
  return property in prototype || (property in style && !UNRENDERED_STYLE_PROPERTIES.has(camel));
2465
2506
  },
@@ -2779,8 +2820,10 @@ const MOUSE_MEMBERS = ["screenX", "screenY", "clientX", "clientY", "pageX", "pag
2779
2820
  /** Event interface → [parent interface, members it owns], parents first. */
2780
2821
  const EVENT_INTERFACES = {
2781
2822
  CustomEvent: ["Event", ["detail", "initCustomEvent"]],
2823
+ AnimationEvent: ["Event", ["animationName", "elapsedTime", "pseudoElement"]],
2782
2824
  UIEvent: ["Event", ["detail", "view", "which", "initUIEvent"]],
2783
2825
  MouseEvent: ["UIEvent", MOUSE_MEMBERS],
2826
+ DragEvent: ["MouseEvent", ["dataTransfer"]],
2784
2827
  PointerEvent: ["MouseEvent", ["pointerType"]],
2785
2828
  WheelEvent: ["MouseEvent", ["deltaX", "deltaY", "deltaMode"]],
2786
2829
  KeyboardEvent: ["UIEvent", ["key", "code", "keyCode", "charCode", "repeat", ...MODIFIERS]],
@@ -2797,11 +2840,11 @@ const CREATE_EVENT_TYPES = new Map([["event", "Event"], ["events", "Event"], ["h
2797
2840
  ["mouseevents", "MouseEvent"], ["keyboardevent", "KeyboardEvent"], ["focusevent", "FocusEvent"],
2798
2841
  ["messageevent", "MessageEvent"], ["hashchangeevent", "HashChangeEvent"], ["popstateevent", "PopStateEvent"]]);
2799
2842
 
2800
- const UI_EVENT_TYPES = ["UIEvent", "MouseEvent", "PointerEvent", "WheelEvent", "KeyboardEvent", "FocusEvent", "InputEvent"];
2843
+ const UI_EVENT_TYPES = ["AnimationEvent", "UIEvent", "MouseEvent", "PointerEvent", "WheelEvent", "KeyboardEvent", "FocusEvent", "InputEvent"];
2801
2844
  const UI_EVENT_FIELDS = [
2802
2845
  ...["detail", "clientX", "clientY", "screenX", "screenY", "button", "buttons", "deltaX", "deltaY", "deltaZ", "deltaMode",
2803
- "pointerId", "width", "height", "pressure", "location", "keyCode", "which", "charCode"].map((key) => [key, Number]),
2804
- ...["key", "code", "data", "inputType", "pointerType"].map((key) => [key, String]),
2846
+ "pointerId", "width", "height", "pressure", "location", "keyCode", "which", "charCode", "elapsedTime"].map((key) => [key, Number]),
2847
+ ...["key", "code", "data", "inputType", "pointerType", "animationName", "pseudoElement"].map((key) => [key, String]),
2805
2848
  ...["ctrlKey", "altKey", "shiftKey", "metaKey", "repeat", "isComposing", "isPrimary"].map((key) => [key, Boolean]),
2806
2849
  ];
2807
2850
 
@@ -2854,7 +2897,17 @@ export function eventConstructors(realm) {
2854
2897
  Object.defineProperty(CustomEvent.prototype, "constructor", { value: CustomEvent, writable: true, configurable: true });
2855
2898
  // UI event subclasses: their init dictionaries are copied as primitives only
2856
2899
  // (view and relatedTarget are dropped).
2857
- const uiEvents = {};
2900
+ function DragEvent(type, options = {}) {
2901
+ if (!new.target) throw new TypeError("Constructor DragEvent requires 'new'");
2902
+ const data=options?.dataTransfer ?? null;
2903
+ if(data!==null && !(data instanceof DataTransfer))throw new TypeError("Invalid dataTransfer");
2904
+ const fields={...init(options)};
2905
+ for(const [key,coerce] of UI_EVENT_FIELDS)if(options?.[key]!==undefined)fields[key]=coerce(options[key]);
2906
+ return realm.wrapEvent(dragEvent(window,String(type),fields,data));
2907
+ }
2908
+ DragEvent.prototype=realm.eventPrototypes.get('DragEvent');
2909
+ Object.defineProperty(DragEvent.prototype,'constructor',{value:DragEvent,writable:true,configurable:true});
2910
+ const uiEvents = {DragEvent,DataTransfer};
2858
2911
  for (const name of UI_EVENT_TYPES) {
2859
2912
  const RealEvent = window[name];
2860
2913
  if (typeof RealEvent !== "function") continue;
@@ -2936,7 +2989,7 @@ function cssEscape(value) {
2936
2989
  * Must run after SES lockdown() (which provides `harden`).
2937
2990
  */
2938
2991
  const BINDINGS = [NodeBinding, CharacterDataBinding, TextBinding, ParentBinding, FragmentBinding, ShadowRootBinding, ElementBinding,
2939
- DocumentBinding, EventBinding, ClassListBinding, TreeWalkerBinding, NodeIteratorBinding, RangeBinding];
2992
+ DocumentBinding, EventBinding, DataTransfer, ClassListBinding, TreeWalkerBinding, NodeIteratorBinding, RangeBinding];
2940
2993
 
2941
2994
  // Members defined with Object.defineProperty({ get() {...} }) are named
2942
2995
  // "get"; Web IDL names an attribute's accessors "get x" / "set x" and an