@openspecui/web 0.9.3 → 1.0.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.
Files changed (89) hide show
  1. package/dist/assets/BufferResource-CVUoegR6.js +185 -0
  2. package/dist/assets/CanvasRenderer-BEIcB8i1.js +1 -0
  3. package/dist/assets/Filter-Bu_qhr6H.js +1 -0
  4. package/dist/assets/RenderTargetSystem-DWouFDxU.js +172 -0
  5. package/dist/assets/WebGLRenderer-6FH_N1FV.js +156 -0
  6. package/dist/assets/WebGPURenderer-B8sJk3Sv.js +41 -0
  7. package/dist/assets/browserAll-CLKeV1yb.js +14 -0
  8. package/dist/assets/gemini-Bk-V9kKu.png +0 -0
  9. package/dist/assets/{index-Bp00uZNc.js → index-BE5-y0_g.js} +1 -1
  10. package/{dist-ssg/client/assets/index-CCfVkFzN.js → dist/assets/index-BPCTI2mG.js} +1 -1
  11. package/dist/assets/{index-BsTieXqQ.js → index-BRp8MJ9v.js} +1 -1
  12. package/dist/assets/{index-8c6bEJ99.js → index-BlZ-sasH.js} +1 -1
  13. package/dist/assets/{index-Bafja8o4.js → index-Bp_dnlLF.js} +1 -1
  14. package/{dist-ssg/client/assets/index-ftYom_wU.js → dist/assets/index-BtNuxyw4.js} +1 -1
  15. package/dist/assets/index-Bv7pWR8R.js +7 -0
  16. package/{dist-ssg/client/assets/index-D3mXuuih.js → dist/assets/index-Byr3HkRi.js} +1 -1
  17. package/dist/assets/index-CEHMo0EU.js +1385 -0
  18. package/dist/assets/{index-eA_XNQ_L.js → index-CEKSUzvw.js} +1 -1
  19. package/dist/assets/index-CEf9wXLh.css +1 -0
  20. package/{dist-ssg/client/assets/index-ArhptQw0.js → dist/assets/index-CX13iBBs.js} +1 -1
  21. package/dist/assets/index-CoOT7eZ9.js +1 -0
  22. package/{dist-ssg/client/assets/index-B1hpa--1.js → dist/assets/index-D4AU46yO.js} +1 -1
  23. package/dist/assets/{index-BvGAWAqS.js → index-DXRZmZm8.js} +1 -1
  24. package/{dist-ssg/client/assets/index-AbWe21oh.js → dist/assets/index-eQZwF8qE.js} +1 -1
  25. package/dist/assets/{index-gvPT4BlL.js → index-mWXhCp9j.js} +1 -1
  26. package/dist/assets/webworkerAll-DjWoTx9g.js +83 -0
  27. package/dist/index.html +2 -2
  28. package/dist-ssg/client/.vite/ssr-manifest.json +3094 -504
  29. package/dist-ssg/client/assets/BufferResource-CVUoegR6.js +185 -0
  30. package/dist-ssg/client/assets/CanvasRenderer-BEIcB8i1.js +1 -0
  31. package/dist-ssg/client/assets/Filter-Bu_qhr6H.js +1 -0
  32. package/dist-ssg/client/assets/RenderTargetSystem-DWouFDxU.js +172 -0
  33. package/dist-ssg/client/assets/WebGLRenderer-6FH_N1FV.js +156 -0
  34. package/dist-ssg/client/assets/WebGPURenderer-B8sJk3Sv.js +41 -0
  35. package/dist-ssg/client/assets/browserAll-CLKeV1yb.js +14 -0
  36. package/dist-ssg/client/assets/gemini-Bk-V9kKu.png +0 -0
  37. package/dist-ssg/client/assets/{index-Bp00uZNc.js → index-BE5-y0_g.js} +1 -1
  38. package/{dist/assets/index-CCfVkFzN.js → dist-ssg/client/assets/index-BPCTI2mG.js} +1 -1
  39. package/dist-ssg/client/assets/{index-BsTieXqQ.js → index-BRp8MJ9v.js} +1 -1
  40. package/dist-ssg/client/assets/{index-8c6bEJ99.js → index-BlZ-sasH.js} +1 -1
  41. package/dist-ssg/client/assets/{index-Bafja8o4.js → index-Bp_dnlLF.js} +1 -1
  42. package/{dist/assets/index-ftYom_wU.js → dist-ssg/client/assets/index-BtNuxyw4.js} +1 -1
  43. package/dist-ssg/client/assets/index-Bv7pWR8R.js +7 -0
  44. package/{dist/assets/index-D3mXuuih.js → dist-ssg/client/assets/index-Byr3HkRi.js} +1 -1
  45. package/dist-ssg/client/assets/index-CEHMo0EU.js +1385 -0
  46. package/dist-ssg/client/assets/{index-eA_XNQ_L.js → index-CEKSUzvw.js} +1 -1
  47. package/dist-ssg/client/assets/index-CEf9wXLh.css +1 -0
  48. package/{dist/assets/index-ArhptQw0.js → dist-ssg/client/assets/index-CX13iBBs.js} +1 -1
  49. package/dist-ssg/client/assets/index-CoOT7eZ9.js +1 -0
  50. package/{dist/assets/index-B1hpa--1.js → dist-ssg/client/assets/index-D4AU46yO.js} +1 -1
  51. package/dist-ssg/client/assets/{index-BvGAWAqS.js → index-DXRZmZm8.js} +1 -1
  52. package/{dist/assets/index-AbWe21oh.js → dist-ssg/client/assets/index-eQZwF8qE.js} +1 -1
  53. package/dist-ssg/client/assets/{index-gvPT4BlL.js → index-mWXhCp9j.js} +1 -1
  54. package/dist-ssg/client/assets/webworkerAll-DjWoTx9g.js +83 -0
  55. package/dist-ssg/client/index.html +2 -2
  56. package/dist-ssg/server/assets/BufferResource-BXrsGVSz.js +592 -0
  57. package/dist-ssg/server/assets/CanvasRenderer-D9aMd7WV.js +1530 -0
  58. package/dist-ssg/server/assets/Filter-ClU0-pLL.js +80 -0
  59. package/dist-ssg/server/assets/RenderTargetSystem-CVz6i60H.js +3037 -0
  60. package/dist-ssg/server/assets/WebGLRenderer-B0I5TP5d.js +3887 -0
  61. package/dist-ssg/server/assets/WebGPURenderer-DCgUFny7.js +2146 -0
  62. package/dist-ssg/server/assets/browserAll-BixK1BYs.js +2691 -0
  63. package/dist-ssg/server/assets/{index-BUANIFyF.js → index-3uSTc-o9.js} +3 -1
  64. package/dist-ssg/server/assets/{index-D0JVKGRJ.js → index-8uE7RyRi.js} +3 -1
  65. package/dist-ssg/server/assets/{index-DCGDP0cs.js → index-BDzDVVaf.js} +2 -0
  66. package/dist-ssg/server/assets/{index-oPcprgZH.js → index-BkJYfA64.js} +3 -1
  67. package/dist-ssg/server/assets/{index-CAP0cmVO.js → index-BvGNqnLD.js} +3 -1
  68. package/dist-ssg/server/assets/{index-DsfT46da.js → index-BvURgefh.js} +3 -1
  69. package/dist-ssg/server/assets/{index-Dk9q2o0C.js → index-C2CuXbSQ.js} +3 -1
  70. package/dist-ssg/server/assets/{index-Cmnd0jiw.js → index-C3RtR5EA.js} +3 -1
  71. package/dist-ssg/server/assets/{index-CFKaffPZ.js → index-CZtnphnE.js} +3 -1
  72. package/dist-ssg/server/assets/{index-D6n8WPGB.js → index-D0DRToHj.js} +3 -1
  73. package/dist-ssg/server/assets/{index-mJoWrrNO.js → index-D5MdLWau.js} +3 -1
  74. package/dist-ssg/server/assets/{index-Brcpp_nj.js → index-DBYODvy4.js} +3 -1
  75. package/dist-ssg/server/assets/{index-DYmgiM6_.js → index-DL23PkQi.js} +3 -1
  76. package/dist-ssg/server/assets/{index-CnRKREoz.js → index-DfcLdBOi.js} +3 -1
  77. package/dist-ssg/server/assets/{index-Bzw5T-vd.js → index-O2XMojWG.js} +3 -1
  78. package/dist-ssg/server/assets/init-CnkBvt-J.js +666 -0
  79. package/dist-ssg/server/assets/webworkerAll-DNiMFaVV.js +12 -0
  80. package/dist-ssg/server/entry-server.js +87120 -34846
  81. package/package.json +23 -5
  82. package/dist/assets/index-D-Urq2hl.css +0 -1
  83. package/dist/assets/index-DFOLYN6W.js +0 -1
  84. package/dist/assets/index-DpxkOmNJ.js +0 -7
  85. package/dist/assets/index-YZ-iXB95.js +0 -309
  86. package/dist-ssg/client/assets/index-D-Urq2hl.css +0 -1
  87. package/dist-ssg/client/assets/index-DFOLYN6W.js +0 -1
  88. package/dist-ssg/client/assets/index-DpxkOmNJ.js +0 -7
  89. package/dist-ssg/client/assets/index-YZ-iXB95.js +0 -309
@@ -0,0 +1,2691 @@
1
+ import { a8 as Ticker, a9 as UPDATE_PRIORITY, aa as Point, ab as removeItems, y as ExtensionType, V as EventEmitter, D as warn, H as extensions, ac as Container } from "../entry-server.js";
2
+ import "./init-CnkBvt-J.js";
3
+ import "util";
4
+ import "crypto";
5
+ import "async_hooks";
6
+ import "stream";
7
+ import "process";
8
+ import "buffer";
9
+ import "node:process";
10
+ import "node:path";
11
+ import "node:url";
12
+ import "./Filter-ClU0-pLL.js";
13
+ class CanvasObserver {
14
+ constructor(options) {
15
+ this._lastTransform = "";
16
+ this._observer = null;
17
+ this._tickerAttached = false;
18
+ this.updateTranslation = () => {
19
+ if (!this._canvas) return;
20
+ const rect = this._canvas.getBoundingClientRect();
21
+ const contentWidth = this._canvas.width;
22
+ const contentHeight = this._canvas.height;
23
+ const sx = rect.width / contentWidth * this._renderer.resolution;
24
+ const sy = rect.height / contentHeight * this._renderer.resolution;
25
+ const tx = rect.left;
26
+ const ty = rect.top;
27
+ const newTransform = `translate(${tx}px, ${ty}px) scale(${sx}, ${sy})`;
28
+ if (newTransform !== this._lastTransform) {
29
+ this._domElement.style.transform = newTransform;
30
+ this._lastTransform = newTransform;
31
+ }
32
+ };
33
+ this._domElement = options.domElement;
34
+ this._renderer = options.renderer;
35
+ if (globalThis.OffscreenCanvas && this._renderer.canvas instanceof OffscreenCanvas) return;
36
+ this._canvas = this._renderer.canvas;
37
+ this._attachObserver();
38
+ }
39
+ /** The canvas element that this CanvasObserver is associated with. */
40
+ get canvas() {
41
+ return this._canvas;
42
+ }
43
+ /** Attaches the DOM element to the canvas parent if it is not already attached. */
44
+ ensureAttached() {
45
+ if (!this._domElement.parentNode && this._canvas.parentNode) {
46
+ this._canvas.parentNode.appendChild(this._domElement);
47
+ this.updateTranslation();
48
+ }
49
+ }
50
+ /** Sets up a ResizeObserver if available. This ensures that the DOM element is kept in sync with the canvas size . */
51
+ _attachObserver() {
52
+ if ("ResizeObserver" in globalThis) {
53
+ if (this._observer) {
54
+ this._observer.disconnect();
55
+ this._observer = null;
56
+ }
57
+ this._observer = new ResizeObserver((entries) => {
58
+ for (const entry of entries) {
59
+ if (entry.target !== this._canvas) {
60
+ continue;
61
+ }
62
+ const contentWidth = this.canvas.width;
63
+ const contentHeight = this.canvas.height;
64
+ const sx = entry.contentRect.width / contentWidth * this._renderer.resolution;
65
+ const sy = entry.contentRect.height / contentHeight * this._renderer.resolution;
66
+ const needsUpdate = this._lastScaleX !== sx || this._lastScaleY !== sy;
67
+ if (needsUpdate) {
68
+ this.updateTranslation();
69
+ this._lastScaleX = sx;
70
+ this._lastScaleY = sy;
71
+ }
72
+ }
73
+ });
74
+ this._observer.observe(this._canvas);
75
+ } else if (!this._tickerAttached) {
76
+ Ticker.shared.add(this.updateTranslation, this, UPDATE_PRIORITY.HIGH);
77
+ }
78
+ }
79
+ /** Destroys the CanvasObserver instance, cleaning up observers and Ticker. */
80
+ destroy() {
81
+ if (this._observer) {
82
+ this._observer.disconnect();
83
+ this._observer = null;
84
+ } else if (this._tickerAttached) {
85
+ Ticker.shared.remove(this.updateTranslation);
86
+ }
87
+ this._domElement = null;
88
+ this._renderer = null;
89
+ this._canvas = null;
90
+ this._tickerAttached = false;
91
+ this._lastTransform = "";
92
+ this._lastScaleX = null;
93
+ this._lastScaleY = null;
94
+ }
95
+ }
96
+ class FederatedEvent {
97
+ /**
98
+ * @param manager - The event boundary which manages this event. Propagation can only occur
99
+ * within the boundary's jurisdiction.
100
+ */
101
+ constructor(manager) {
102
+ this.bubbles = true;
103
+ this.cancelBubble = true;
104
+ this.cancelable = false;
105
+ this.composed = false;
106
+ this.defaultPrevented = false;
107
+ this.eventPhase = FederatedEvent.prototype.NONE;
108
+ this.propagationStopped = false;
109
+ this.propagationImmediatelyStopped = false;
110
+ this.layer = new Point();
111
+ this.page = new Point();
112
+ this.NONE = 0;
113
+ this.CAPTURING_PHASE = 1;
114
+ this.AT_TARGET = 2;
115
+ this.BUBBLING_PHASE = 3;
116
+ this.manager = manager;
117
+ }
118
+ /** @readonly */
119
+ get layerX() {
120
+ return this.layer.x;
121
+ }
122
+ /** @readonly */
123
+ get layerY() {
124
+ return this.layer.y;
125
+ }
126
+ /** @readonly */
127
+ get pageX() {
128
+ return this.page.x;
129
+ }
130
+ /** @readonly */
131
+ get pageY() {
132
+ return this.page.y;
133
+ }
134
+ /**
135
+ * Fallback for the deprecated `InteractionEvent.data`.
136
+ * @deprecated since 7.0.0
137
+ */
138
+ get data() {
139
+ return this;
140
+ }
141
+ /**
142
+ * The propagation path for this event. Alias for {@link EventBoundary.propagationPath}.
143
+ * @advanced
144
+ */
145
+ composedPath() {
146
+ if (this.manager && (!this.path || this.path[this.path.length - 1] !== this.target)) {
147
+ this.path = this.target ? this.manager.propagationPath(this.target) : [];
148
+ }
149
+ return this.path;
150
+ }
151
+ /**
152
+ * Unimplemented method included for implementing the DOM interface `Event`. It will throw an `Error`.
153
+ * @deprecated
154
+ * @ignore
155
+ * @param _type
156
+ * @param _bubbles
157
+ * @param _cancelable
158
+ */
159
+ initEvent(_type, _bubbles, _cancelable) {
160
+ throw new Error("initEvent() is a legacy DOM API. It is not implemented in the Federated Events API.");
161
+ }
162
+ /**
163
+ * Unimplemented method included for implementing the DOM interface `UIEvent`. It will throw an `Error`.
164
+ * @ignore
165
+ * @deprecated
166
+ * @param _typeArg
167
+ * @param _bubblesArg
168
+ * @param _cancelableArg
169
+ * @param _viewArg
170
+ * @param _detailArg
171
+ */
172
+ initUIEvent(_typeArg, _bubblesArg, _cancelableArg, _viewArg, _detailArg) {
173
+ throw new Error("initUIEvent() is a legacy DOM API. It is not implemented in the Federated Events API.");
174
+ }
175
+ /**
176
+ * Prevent default behavior of both PixiJS and the user agent.
177
+ * @example
178
+ * ```ts
179
+ * sprite.on('click', (event) => {
180
+ * // Prevent both browser's default click behavior
181
+ * // and PixiJS's default handling
182
+ * event.preventDefault();
183
+ *
184
+ * // Custom handling
185
+ * customClickHandler();
186
+ * });
187
+ * ```
188
+ * @remarks
189
+ * - Only works if the native event is cancelable
190
+ * - Does not stop event propagation
191
+ */
192
+ preventDefault() {
193
+ if (this.nativeEvent instanceof Event && this.nativeEvent.cancelable) {
194
+ this.nativeEvent.preventDefault();
195
+ }
196
+ this.defaultPrevented = true;
197
+ }
198
+ /**
199
+ * Stop this event from propagating to any additional listeners, including those
200
+ * on the current target and any following targets in the propagation path.
201
+ * @example
202
+ * ```ts
203
+ * container.on('pointerdown', (event) => {
204
+ * // Stop all further event handling
205
+ * event.stopImmediatePropagation();
206
+ *
207
+ * // These handlers won't be called:
208
+ * // - Other pointerdown listeners on this container
209
+ * // - Any pointerdown listeners on parent containers
210
+ * });
211
+ * ```
212
+ * @remarks
213
+ * - Immediately stops all event propagation
214
+ * - Prevents other listeners on same target from being called
215
+ * - More aggressive than stopPropagation()
216
+ */
217
+ stopImmediatePropagation() {
218
+ this.propagationImmediatelyStopped = true;
219
+ }
220
+ /**
221
+ * Stop this event from propagating to the next target in the propagation path.
222
+ * The rest of the listeners on the current target will still be notified.
223
+ * @example
224
+ * ```ts
225
+ * child.on('pointermove', (event) => {
226
+ * // Handle event on child
227
+ * updateChild();
228
+ *
229
+ * // Prevent parent handlers from being called
230
+ * event.stopPropagation();
231
+ * });
232
+ *
233
+ * // This won't be called if child handles the event
234
+ * parent.on('pointermove', (event) => {
235
+ * updateParent();
236
+ * });
237
+ * ```
238
+ * @remarks
239
+ * - Stops event bubbling to parent containers
240
+ * - Does not prevent other listeners on same target
241
+ * - Less aggressive than stopImmediatePropagation()
242
+ */
243
+ stopPropagation() {
244
+ this.propagationStopped = true;
245
+ }
246
+ }
247
+ var appleIphone = /iPhone/i;
248
+ var appleIpod = /iPod/i;
249
+ var appleTablet = /iPad/i;
250
+ var appleUniversal = /\biOS-universal(?:.+)Mac\b/i;
251
+ var androidPhone = /\bAndroid(?:.+)Mobile\b/i;
252
+ var androidTablet = /Android/i;
253
+ var amazonPhone = /(?:SD4930UR|\bSilk(?:.+)Mobile\b)/i;
254
+ var amazonTablet = /Silk/i;
255
+ var windowsPhone = /Windows Phone/i;
256
+ var windowsTablet = /\bWindows(?:.+)ARM\b/i;
257
+ var otherBlackBerry = /BlackBerry/i;
258
+ var otherBlackBerry10 = /BB10/i;
259
+ var otherOpera = /Opera Mini/i;
260
+ var otherChrome = /\b(CriOS|Chrome)(?:.+)Mobile/i;
261
+ var otherFirefox = /Mobile(?:.+)Firefox\b/i;
262
+ var isAppleTabletOnIos13 = function(navigator2) {
263
+ return typeof navigator2 !== "undefined" && navigator2.platform === "MacIntel" && typeof navigator2.maxTouchPoints === "number" && navigator2.maxTouchPoints > 1 && typeof MSStream === "undefined";
264
+ };
265
+ function createMatch(userAgent) {
266
+ return function(regex) {
267
+ return regex.test(userAgent);
268
+ };
269
+ }
270
+ function isMobile$1(param) {
271
+ var nav = {
272
+ userAgent: "",
273
+ platform: "",
274
+ maxTouchPoints: 0
275
+ };
276
+ if (!param && typeof navigator !== "undefined") {
277
+ nav = {
278
+ userAgent: navigator.userAgent,
279
+ platform: navigator.platform,
280
+ maxTouchPoints: navigator.maxTouchPoints || 0
281
+ };
282
+ } else if (typeof param === "string") {
283
+ nav.userAgent = param;
284
+ } else if (param && param.userAgent) {
285
+ nav = {
286
+ userAgent: param.userAgent,
287
+ platform: param.platform,
288
+ maxTouchPoints: param.maxTouchPoints || 0
289
+ };
290
+ }
291
+ var userAgent = nav.userAgent;
292
+ var tmp = userAgent.split("[FBAN");
293
+ if (typeof tmp[1] !== "undefined") {
294
+ userAgent = tmp[0];
295
+ }
296
+ tmp = userAgent.split("Twitter");
297
+ if (typeof tmp[1] !== "undefined") {
298
+ userAgent = tmp[0];
299
+ }
300
+ var match = createMatch(userAgent);
301
+ var result = {
302
+ apple: {
303
+ phone: match(appleIphone) && !match(windowsPhone),
304
+ ipod: match(appleIpod),
305
+ tablet: !match(appleIphone) && (match(appleTablet) || isAppleTabletOnIos13(nav)) && !match(windowsPhone),
306
+ universal: match(appleUniversal),
307
+ device: (match(appleIphone) || match(appleIpod) || match(appleTablet) || match(appleUniversal) || isAppleTabletOnIos13(nav)) && !match(windowsPhone)
308
+ },
309
+ amazon: {
310
+ phone: match(amazonPhone),
311
+ tablet: !match(amazonPhone) && match(amazonTablet),
312
+ device: match(amazonPhone) || match(amazonTablet)
313
+ },
314
+ android: {
315
+ phone: !match(windowsPhone) && match(amazonPhone) || !match(windowsPhone) && match(androidPhone),
316
+ tablet: !match(windowsPhone) && !match(amazonPhone) && !match(androidPhone) && (match(amazonTablet) || match(androidTablet)),
317
+ device: !match(windowsPhone) && (match(amazonPhone) || match(amazonTablet) || match(androidPhone) || match(androidTablet)) || match(/\bokhttp\b/i)
318
+ },
319
+ windows: {
320
+ phone: match(windowsPhone),
321
+ tablet: match(windowsTablet),
322
+ device: match(windowsPhone) || match(windowsTablet)
323
+ },
324
+ other: {
325
+ blackberry: match(otherBlackBerry),
326
+ blackberry10: match(otherBlackBerry10),
327
+ opera: match(otherOpera),
328
+ firefox: match(otherFirefox),
329
+ chrome: match(otherChrome),
330
+ device: match(otherBlackBerry) || match(otherBlackBerry10) || match(otherOpera) || match(otherFirefox) || match(otherChrome)
331
+ },
332
+ any: false,
333
+ phone: false,
334
+ tablet: false
335
+ };
336
+ result.any = result.apple.device || result.android.device || result.windows.device || result.other.device;
337
+ result.phone = result.apple.phone || result.android.phone || result.windows.phone;
338
+ result.tablet = result.apple.tablet || result.android.tablet || result.windows.tablet;
339
+ return result;
340
+ }
341
+ const isMobileCall = isMobile$1.default ?? isMobile$1;
342
+ const isMobile = isMobileCall(globalThis.navigator);
343
+ const KEY_CODE_TAB = 9;
344
+ const DIV_TOUCH_SIZE = 100;
345
+ const DIV_TOUCH_POS_X = 0;
346
+ const DIV_TOUCH_POS_Y = 0;
347
+ const DIV_TOUCH_ZINDEX = 2;
348
+ const DIV_HOOK_SIZE = 1;
349
+ const DIV_HOOK_POS_X = -1e3;
350
+ const DIV_HOOK_POS_Y = -1e3;
351
+ const DIV_HOOK_ZINDEX = 2;
352
+ const _AccessibilitySystem = class _AccessibilitySystem2 {
353
+ // eslint-disable-next-line jsdoc/require-param
354
+ /**
355
+ * @param {WebGLRenderer|WebGPURenderer} renderer - A reference to the current renderer
356
+ */
357
+ constructor(renderer, _mobileInfo = isMobile) {
358
+ this._mobileInfo = _mobileInfo;
359
+ this.debug = false;
360
+ this._activateOnTab = true;
361
+ this._deactivateOnMouseMove = true;
362
+ this._isActive = false;
363
+ this._isMobileAccessibility = false;
364
+ this._div = null;
365
+ this._pools = {};
366
+ this._renderId = 0;
367
+ this._children = [];
368
+ this._androidUpdateCount = 0;
369
+ this._androidUpdateFrequency = 500;
370
+ this._isRunningTests = false;
371
+ this._boundOnKeyDown = this._onKeyDown.bind(this);
372
+ this._boundOnMouseMove = this._onMouseMove.bind(this);
373
+ this._hookDiv = null;
374
+ if (_mobileInfo.tablet || _mobileInfo.phone) {
375
+ this._createTouchHook();
376
+ }
377
+ this._renderer = renderer;
378
+ }
379
+ /**
380
+ * Value of `true` if accessibility is currently active and accessibility layers are showing.
381
+ * @type {boolean}
382
+ * @readonly
383
+ */
384
+ get isActive() {
385
+ return this._isActive;
386
+ }
387
+ /**
388
+ * Value of `true` if accessibility is enabled for touch devices.
389
+ * @type {boolean}
390
+ * @readonly
391
+ */
392
+ get isMobileAccessibility() {
393
+ return this._isMobileAccessibility;
394
+ }
395
+ /**
396
+ * Button element for handling touch hooks.
397
+ * @readonly
398
+ */
399
+ get hookDiv() {
400
+ return this._hookDiv;
401
+ }
402
+ /**
403
+ * The DOM element that will sit over the PixiJS element. This is where the div overlays will go.
404
+ * @readonly
405
+ */
406
+ get div() {
407
+ return this._div;
408
+ }
409
+ /**
410
+ * Creates the touch hooks.
411
+ * @private
412
+ */
413
+ _createTouchHook() {
414
+ const hookDiv = document.createElement("button");
415
+ hookDiv.style.width = `${DIV_HOOK_SIZE}px`;
416
+ hookDiv.style.height = `${DIV_HOOK_SIZE}px`;
417
+ hookDiv.style.position = "absolute";
418
+ hookDiv.style.top = `${DIV_HOOK_POS_X}px`;
419
+ hookDiv.style.left = `${DIV_HOOK_POS_Y}px`;
420
+ hookDiv.style.zIndex = DIV_HOOK_ZINDEX.toString();
421
+ hookDiv.style.backgroundColor = "#FF0000";
422
+ hookDiv.title = "select to enable accessibility for this content";
423
+ hookDiv.addEventListener("focus", () => {
424
+ this._isMobileAccessibility = true;
425
+ this._activate();
426
+ this._destroyTouchHook();
427
+ });
428
+ document.body.appendChild(hookDiv);
429
+ this._hookDiv = hookDiv;
430
+ }
431
+ /**
432
+ * Destroys the touch hooks.
433
+ * @private
434
+ */
435
+ _destroyTouchHook() {
436
+ if (!this._hookDiv) {
437
+ return;
438
+ }
439
+ document.body.removeChild(this._hookDiv);
440
+ this._hookDiv = null;
441
+ }
442
+ /**
443
+ * Activating will cause the Accessibility layer to be shown.
444
+ * This is called when a user presses the tab key.
445
+ * @private
446
+ */
447
+ _activate() {
448
+ if (this._isActive) {
449
+ return;
450
+ }
451
+ this._isActive = true;
452
+ if (!this._div) {
453
+ this._div = document.createElement("div");
454
+ this._div.style.position = "absolute";
455
+ this._div.style.top = `${DIV_TOUCH_POS_X}px`;
456
+ this._div.style.left = `${DIV_TOUCH_POS_Y}px`;
457
+ this._div.style.pointerEvents = "none";
458
+ this._div.style.zIndex = DIV_TOUCH_ZINDEX.toString();
459
+ this._canvasObserver = new CanvasObserver({
460
+ domElement: this._div,
461
+ renderer: this._renderer
462
+ });
463
+ }
464
+ if (this._activateOnTab) {
465
+ globalThis.addEventListener("keydown", this._boundOnKeyDown, false);
466
+ }
467
+ if (this._deactivateOnMouseMove) {
468
+ globalThis.document.addEventListener("mousemove", this._boundOnMouseMove, true);
469
+ }
470
+ const canvas = this._renderer.view.canvas;
471
+ if (!canvas.parentNode) {
472
+ const observer = new MutationObserver(() => {
473
+ if (canvas.parentNode) {
474
+ observer.disconnect();
475
+ this._canvasObserver.ensureAttached();
476
+ this._initAccessibilitySetup();
477
+ }
478
+ });
479
+ observer.observe(document.body, { childList: true, subtree: true });
480
+ } else {
481
+ this._canvasObserver.ensureAttached();
482
+ this._initAccessibilitySetup();
483
+ }
484
+ }
485
+ // New method to handle initialization after div is ready
486
+ _initAccessibilitySetup() {
487
+ this._renderer.runners.postrender.add(this);
488
+ if (this._renderer.lastObjectRendered) {
489
+ this._updateAccessibleObjects(this._renderer.lastObjectRendered);
490
+ }
491
+ }
492
+ /**
493
+ * Deactivates the accessibility system. Removes listeners and accessibility elements.
494
+ * @private
495
+ */
496
+ _deactivate() {
497
+ if (!this._isActive || this._isMobileAccessibility) {
498
+ return;
499
+ }
500
+ this._isActive = false;
501
+ globalThis.document.removeEventListener("mousemove", this._boundOnMouseMove, true);
502
+ if (this._activateOnTab) {
503
+ globalThis.addEventListener("keydown", this._boundOnKeyDown, false);
504
+ }
505
+ this._renderer.runners.postrender.remove(this);
506
+ for (const child of this._children) {
507
+ if (child._accessibleDiv?.parentNode) {
508
+ child._accessibleDiv.parentNode.removeChild(child._accessibleDiv);
509
+ child._accessibleDiv = null;
510
+ }
511
+ child._accessibleActive = false;
512
+ }
513
+ for (const accessibleType in this._pools) {
514
+ const pool = this._pools[accessibleType];
515
+ pool.forEach((div) => {
516
+ if (div.parentNode) {
517
+ div.parentNode.removeChild(div);
518
+ }
519
+ });
520
+ delete this._pools[accessibleType];
521
+ }
522
+ if (this._div?.parentNode) {
523
+ this._div.parentNode.removeChild(this._div);
524
+ }
525
+ this._pools = {};
526
+ this._children = [];
527
+ }
528
+ /**
529
+ * This recursive function will run through the scene graph and add any new accessible objects to the DOM layer.
530
+ * @private
531
+ * @param {Container} container - The Container to check.
532
+ */
533
+ _updateAccessibleObjects(container) {
534
+ if (!container.visible || !container.accessibleChildren) {
535
+ return;
536
+ }
537
+ if (container.accessible) {
538
+ if (!container._accessibleActive) {
539
+ this._addChild(container);
540
+ }
541
+ container._renderId = this._renderId;
542
+ }
543
+ const children = container.children;
544
+ if (children) {
545
+ for (let i = 0; i < children.length; i++) {
546
+ this._updateAccessibleObjects(children[i]);
547
+ }
548
+ }
549
+ }
550
+ /**
551
+ * Runner init called, view is available at this point.
552
+ * @ignore
553
+ */
554
+ init(options) {
555
+ const defaultOpts = _AccessibilitySystem2.defaultOptions;
556
+ const mergedOptions = {
557
+ accessibilityOptions: {
558
+ ...defaultOpts,
559
+ ...options?.accessibilityOptions || {}
560
+ }
561
+ };
562
+ this.debug = mergedOptions.accessibilityOptions.debug;
563
+ this._activateOnTab = mergedOptions.accessibilityOptions.activateOnTab;
564
+ this._deactivateOnMouseMove = mergedOptions.accessibilityOptions.deactivateOnMouseMove;
565
+ if (mergedOptions.accessibilityOptions.enabledByDefault) {
566
+ this._activate();
567
+ }
568
+ this._renderer.runners.postrender.remove(this);
569
+ }
570
+ /**
571
+ * Updates the accessibility layer during rendering.
572
+ * - Removes divs for containers no longer in the scene
573
+ * - Updates the position and dimensions of the root div
574
+ * - Updates positions of active accessibility divs
575
+ * Only fires while the accessibility system is active.
576
+ * @ignore
577
+ */
578
+ postrender() {
579
+ const now = performance.now();
580
+ if (this._mobileInfo.android.device && now < this._androidUpdateCount) {
581
+ return;
582
+ }
583
+ this._androidUpdateCount = now + this._androidUpdateFrequency;
584
+ if ((!this._renderer.renderingToScreen || !this._renderer.view.canvas) && !this._isRunningTests) {
585
+ return;
586
+ }
587
+ const activeIds = /* @__PURE__ */ new Set();
588
+ if (this._renderer.lastObjectRendered) {
589
+ this._updateAccessibleObjects(this._renderer.lastObjectRendered);
590
+ for (const child of this._children) {
591
+ if (child._renderId === this._renderId) {
592
+ activeIds.add(this._children.indexOf(child));
593
+ }
594
+ }
595
+ }
596
+ for (let i = this._children.length - 1; i >= 0; i--) {
597
+ const child = this._children[i];
598
+ if (!activeIds.has(i)) {
599
+ if (child._accessibleDiv && child._accessibleDiv.parentNode) {
600
+ child._accessibleDiv.parentNode.removeChild(child._accessibleDiv);
601
+ const pool = this._getPool(child.accessibleType);
602
+ pool.push(child._accessibleDiv);
603
+ child._accessibleDiv = null;
604
+ }
605
+ child._accessibleActive = false;
606
+ removeItems(this._children, i, 1);
607
+ }
608
+ }
609
+ if (this._renderer.renderingToScreen) {
610
+ this._canvasObserver.ensureAttached();
611
+ }
612
+ for (let i = 0; i < this._children.length; i++) {
613
+ const child = this._children[i];
614
+ if (!child._accessibleActive || !child._accessibleDiv) {
615
+ continue;
616
+ }
617
+ const div = child._accessibleDiv;
618
+ const hitArea = child.hitArea || child.getBounds().rectangle;
619
+ if (child.hitArea) {
620
+ const wt = child.worldTransform;
621
+ div.style.left = `${wt.tx + hitArea.x * wt.a}px`;
622
+ div.style.top = `${wt.ty + hitArea.y * wt.d}px`;
623
+ div.style.width = `${hitArea.width * wt.a}px`;
624
+ div.style.height = `${hitArea.height * wt.d}px`;
625
+ } else {
626
+ this._capHitArea(hitArea);
627
+ div.style.left = `${hitArea.x}px`;
628
+ div.style.top = `${hitArea.y}px`;
629
+ div.style.width = `${hitArea.width}px`;
630
+ div.style.height = `${hitArea.height}px`;
631
+ }
632
+ }
633
+ this._renderId++;
634
+ }
635
+ /**
636
+ * private function that will visually add the information to the
637
+ * accessibility div
638
+ * @param {HTMLElement} div -
639
+ */
640
+ _updateDebugHTML(div) {
641
+ div.innerHTML = `type: ${div.type}</br> title : ${div.title}</br> tabIndex: ${div.tabIndex}`;
642
+ }
643
+ /**
644
+ * Adjust the hit area based on the bounds of a display object
645
+ * @param {Rectangle} hitArea - Bounds of the child
646
+ */
647
+ _capHitArea(hitArea) {
648
+ if (hitArea.x < 0) {
649
+ hitArea.width += hitArea.x;
650
+ hitArea.x = 0;
651
+ }
652
+ if (hitArea.y < 0) {
653
+ hitArea.height += hitArea.y;
654
+ hitArea.y = 0;
655
+ }
656
+ const { width: viewWidth, height: viewHeight } = this._renderer;
657
+ if (hitArea.x + hitArea.width > viewWidth) {
658
+ hitArea.width = viewWidth - hitArea.x;
659
+ }
660
+ if (hitArea.y + hitArea.height > viewHeight) {
661
+ hitArea.height = viewHeight - hitArea.y;
662
+ }
663
+ }
664
+ /**
665
+ * Creates or reuses a div element for a Container and adds it to the accessibility layer.
666
+ * Sets up ARIA attributes, event listeners, and positioning based on the container's properties.
667
+ * @private
668
+ * @param {Container} container - The child to make accessible.
669
+ */
670
+ _addChild(container) {
671
+ const pool = this._getPool(container.accessibleType);
672
+ let div = pool.pop();
673
+ if (div) {
674
+ div.innerHTML = "";
675
+ div.removeAttribute("title");
676
+ div.removeAttribute("aria-label");
677
+ div.tabIndex = 0;
678
+ } else {
679
+ if (container.accessibleType === "button") {
680
+ div = document.createElement("button");
681
+ } else {
682
+ div = document.createElement(container.accessibleType);
683
+ div.style.cssText = `
684
+ color: transparent;
685
+ pointer-events: none;
686
+ padding: 0;
687
+ margin: 0;
688
+ border: 0;
689
+ outline: 0;
690
+ background: transparent;
691
+ box-sizing: border-box;
692
+ user-select: none;
693
+ -webkit-user-select: none;
694
+ -moz-user-select: none;
695
+ -ms-user-select: none;
696
+ `;
697
+ if (container.accessibleText) {
698
+ div.innerText = container.accessibleText;
699
+ }
700
+ }
701
+ div.style.width = `${DIV_TOUCH_SIZE}px`;
702
+ div.style.height = `${DIV_TOUCH_SIZE}px`;
703
+ div.style.backgroundColor = this.debug ? "rgba(255,255,255,0.5)" : "transparent";
704
+ div.style.position = "absolute";
705
+ div.style.zIndex = DIV_TOUCH_ZINDEX.toString();
706
+ div.style.borderStyle = "none";
707
+ if (navigator.userAgent.toLowerCase().includes("chrome")) {
708
+ div.setAttribute("aria-live", "off");
709
+ } else {
710
+ div.setAttribute("aria-live", "polite");
711
+ }
712
+ if (navigator.userAgent.match(/rv:.*Gecko\//)) {
713
+ div.setAttribute("aria-relevant", "additions");
714
+ } else {
715
+ div.setAttribute("aria-relevant", "text");
716
+ }
717
+ div.addEventListener("click", this._onClick.bind(this));
718
+ div.addEventListener("focus", this._onFocus.bind(this));
719
+ div.addEventListener("focusout", this._onFocusOut.bind(this));
720
+ }
721
+ div.style.pointerEvents = container.accessiblePointerEvents;
722
+ div.type = container.accessibleType;
723
+ if (container.accessibleTitle && container.accessibleTitle !== null) {
724
+ div.title = container.accessibleTitle;
725
+ } else if (!container.accessibleHint || container.accessibleHint === null) {
726
+ div.title = `container ${container.tabIndex}`;
727
+ }
728
+ if (container.accessibleHint && container.accessibleHint !== null) {
729
+ div.setAttribute("aria-label", container.accessibleHint);
730
+ }
731
+ if (container.interactive) {
732
+ div.tabIndex = container.tabIndex;
733
+ } else {
734
+ div.tabIndex = 0;
735
+ }
736
+ if (this.debug) {
737
+ this._updateDebugHTML(div);
738
+ }
739
+ container._accessibleActive = true;
740
+ container._accessibleDiv = div;
741
+ div.container = container;
742
+ this._children.push(container);
743
+ this._div.appendChild(container._accessibleDiv);
744
+ }
745
+ /**
746
+ * Dispatch events with the EventSystem.
747
+ * @param e
748
+ * @param type
749
+ * @private
750
+ */
751
+ _dispatchEvent(e, type) {
752
+ const { container: target } = e.target;
753
+ const boundary = this._renderer.events.rootBoundary;
754
+ const event = Object.assign(new FederatedEvent(boundary), { target });
755
+ boundary.rootTarget = this._renderer.lastObjectRendered;
756
+ type.forEach((type2) => boundary.dispatchEvent(event, type2));
757
+ }
758
+ /**
759
+ * Maps the div button press to pixi's EventSystem (click)
760
+ * @private
761
+ * @param {MouseEvent} e - The click event.
762
+ */
763
+ _onClick(e) {
764
+ this._dispatchEvent(e, ["click", "pointertap", "tap"]);
765
+ }
766
+ /**
767
+ * Maps the div focus events to pixi's EventSystem (mouseover)
768
+ * @private
769
+ * @param {FocusEvent} e - The focus event.
770
+ */
771
+ _onFocus(e) {
772
+ if (!e.target.getAttribute("aria-live")) {
773
+ e.target.setAttribute("aria-live", "assertive");
774
+ }
775
+ this._dispatchEvent(e, ["mouseover"]);
776
+ }
777
+ /**
778
+ * Maps the div focus events to pixi's EventSystem (mouseout)
779
+ * @private
780
+ * @param {FocusEvent} e - The focusout event.
781
+ */
782
+ _onFocusOut(e) {
783
+ if (!e.target.getAttribute("aria-live")) {
784
+ e.target.setAttribute("aria-live", "polite");
785
+ }
786
+ this._dispatchEvent(e, ["mouseout"]);
787
+ }
788
+ /**
789
+ * Is called when a key is pressed
790
+ * @private
791
+ * @param {KeyboardEvent} e - The keydown event.
792
+ */
793
+ _onKeyDown(e) {
794
+ if (e.keyCode !== KEY_CODE_TAB || !this._activateOnTab) {
795
+ return;
796
+ }
797
+ this._activate();
798
+ }
799
+ /**
800
+ * Is called when the mouse moves across the renderer element
801
+ * @private
802
+ * @param {MouseEvent} e - The mouse event.
803
+ */
804
+ _onMouseMove(e) {
805
+ if (e.movementX === 0 && e.movementY === 0) {
806
+ return;
807
+ }
808
+ this._deactivate();
809
+ }
810
+ /**
811
+ * Destroys the accessibility system. Removes all elements and listeners.
812
+ * > [!IMPORTANT] This is typically called automatically when the {@link Application} is destroyed.
813
+ * > A typically user should not need to call this method directly.
814
+ */
815
+ destroy() {
816
+ this._deactivate();
817
+ this._destroyTouchHook();
818
+ this._canvasObserver?.destroy();
819
+ this._canvasObserver = null;
820
+ this._div = null;
821
+ this._pools = null;
822
+ this._children = null;
823
+ this._renderer = null;
824
+ this._hookDiv = null;
825
+ globalThis.removeEventListener("keydown", this._boundOnKeyDown);
826
+ this._boundOnKeyDown = null;
827
+ globalThis.document.removeEventListener("mousemove", this._boundOnMouseMove, true);
828
+ this._boundOnMouseMove = null;
829
+ }
830
+ /**
831
+ * Enables or disables the accessibility system.
832
+ * @param enabled - Whether to enable or disable accessibility.
833
+ * @example
834
+ * ```js
835
+ * app.renderer.accessibility.setAccessibilityEnabled(true); // Enable accessibility
836
+ * app.renderer.accessibility.setAccessibilityEnabled(false); // Disable accessibility
837
+ * ```
838
+ */
839
+ setAccessibilityEnabled(enabled) {
840
+ if (enabled) {
841
+ this._activate();
842
+ } else {
843
+ this._deactivate();
844
+ }
845
+ }
846
+ _getPool(accessibleType) {
847
+ if (!this._pools[accessibleType]) {
848
+ this._pools[accessibleType] = [];
849
+ }
850
+ return this._pools[accessibleType];
851
+ }
852
+ };
853
+ _AccessibilitySystem.extension = {
854
+ type: [
855
+ ExtensionType.WebGLSystem,
856
+ ExtensionType.WebGPUSystem
857
+ ],
858
+ name: "accessibility"
859
+ };
860
+ _AccessibilitySystem.defaultOptions = {
861
+ /**
862
+ * Whether to enable accessibility features on initialization
863
+ * @default false
864
+ */
865
+ enabledByDefault: false,
866
+ /**
867
+ * Whether to visually show the accessibility divs for debugging
868
+ * @default false
869
+ */
870
+ debug: false,
871
+ /**
872
+ * Whether to activate accessibility when tab key is pressed
873
+ * @default true
874
+ */
875
+ activateOnTab: true,
876
+ /**
877
+ * Whether to deactivate accessibility when mouse moves
878
+ * @default true
879
+ */
880
+ deactivateOnMouseMove: true
881
+ };
882
+ let AccessibilitySystem = _AccessibilitySystem;
883
+ const accessibilityTarget = {
884
+ accessible: false,
885
+ accessibleTitle: null,
886
+ accessibleHint: null,
887
+ tabIndex: 0,
888
+ accessibleType: "button",
889
+ accessibleText: null,
890
+ accessiblePointerEvents: "auto",
891
+ accessibleChildren: true,
892
+ _accessibleActive: false,
893
+ _accessibleDiv: null,
894
+ _renderId: -1
895
+ };
896
+ class EventsTickerClass {
897
+ constructor() {
898
+ this.interactionFrequency = 10;
899
+ this._deltaTime = 0;
900
+ this._didMove = false;
901
+ this._tickerAdded = false;
902
+ this._pauseUpdate = true;
903
+ }
904
+ /**
905
+ * Initializes the event ticker.
906
+ * @param events - The event system.
907
+ */
908
+ init(events) {
909
+ this.removeTickerListener();
910
+ this.events = events;
911
+ this.interactionFrequency = 10;
912
+ this._deltaTime = 0;
913
+ this._didMove = false;
914
+ this._tickerAdded = false;
915
+ this._pauseUpdate = true;
916
+ }
917
+ /** Whether to pause the update checks or not. */
918
+ get pauseUpdate() {
919
+ return this._pauseUpdate;
920
+ }
921
+ set pauseUpdate(paused) {
922
+ this._pauseUpdate = paused;
923
+ }
924
+ /** Adds the ticker listener. */
925
+ addTickerListener() {
926
+ if (this._tickerAdded || !this.domElement) {
927
+ return;
928
+ }
929
+ Ticker.system.add(this._tickerUpdate, this, UPDATE_PRIORITY.INTERACTION);
930
+ this._tickerAdded = true;
931
+ }
932
+ /** Removes the ticker listener. */
933
+ removeTickerListener() {
934
+ if (!this._tickerAdded) {
935
+ return;
936
+ }
937
+ Ticker.system.remove(this._tickerUpdate, this);
938
+ this._tickerAdded = false;
939
+ }
940
+ /** Sets flag to not fire extra events when the user has already moved there mouse */
941
+ pointerMoved() {
942
+ this._didMove = true;
943
+ }
944
+ /** Updates the state of interactive objects. */
945
+ _update() {
946
+ if (!this.domElement || this._pauseUpdate) {
947
+ return;
948
+ }
949
+ if (this._didMove) {
950
+ this._didMove = false;
951
+ return;
952
+ }
953
+ const rootPointerEvent = this.events["_rootPointerEvent"];
954
+ if (this.events.supportsTouchEvents && rootPointerEvent.pointerType === "touch") {
955
+ return;
956
+ }
957
+ globalThis.document.dispatchEvent(this.events.supportsPointerEvents ? new PointerEvent("pointermove", {
958
+ clientX: rootPointerEvent.clientX,
959
+ clientY: rootPointerEvent.clientY,
960
+ pointerType: rootPointerEvent.pointerType,
961
+ pointerId: rootPointerEvent.pointerId
962
+ }) : new MouseEvent("mousemove", {
963
+ clientX: rootPointerEvent.clientX,
964
+ clientY: rootPointerEvent.clientY
965
+ }));
966
+ }
967
+ /**
968
+ * Updates the state of interactive objects if at least {@link interactionFrequency}
969
+ * milliseconds have passed since the last invocation.
970
+ *
971
+ * Invoked by a throttled ticker update from {@link Ticker.system}.
972
+ * @param ticker - The throttled ticker.
973
+ */
974
+ _tickerUpdate(ticker) {
975
+ this._deltaTime += ticker.deltaTime;
976
+ if (this._deltaTime < this.interactionFrequency) {
977
+ return;
978
+ }
979
+ this._deltaTime = 0;
980
+ this._update();
981
+ }
982
+ /** Destroys the event ticker. */
983
+ destroy() {
984
+ this.removeTickerListener();
985
+ this.events = null;
986
+ this.domElement = null;
987
+ this._deltaTime = 0;
988
+ this._didMove = false;
989
+ this._tickerAdded = false;
990
+ this._pauseUpdate = true;
991
+ }
992
+ }
993
+ const EventsTicker = new EventsTickerClass();
994
+ class FederatedMouseEvent extends FederatedEvent {
995
+ constructor() {
996
+ super(...arguments);
997
+ this.client = new Point();
998
+ this.movement = new Point();
999
+ this.offset = new Point();
1000
+ this.global = new Point();
1001
+ this.screen = new Point();
1002
+ }
1003
+ /** @readonly */
1004
+ get clientX() {
1005
+ return this.client.x;
1006
+ }
1007
+ /** @readonly */
1008
+ get clientY() {
1009
+ return this.client.y;
1010
+ }
1011
+ /**
1012
+ * Alias for {@link FederatedMouseEvent.clientX this.clientX}.
1013
+ * @readonly
1014
+ */
1015
+ get x() {
1016
+ return this.clientX;
1017
+ }
1018
+ /**
1019
+ * Alias for {@link FederatedMouseEvent.clientY this.clientY}.
1020
+ * @readonly
1021
+ */
1022
+ get y() {
1023
+ return this.clientY;
1024
+ }
1025
+ /** @readonly */
1026
+ get movementX() {
1027
+ return this.movement.x;
1028
+ }
1029
+ /** @readonly */
1030
+ get movementY() {
1031
+ return this.movement.y;
1032
+ }
1033
+ /** @readonly */
1034
+ get offsetX() {
1035
+ return this.offset.x;
1036
+ }
1037
+ /** @readonly */
1038
+ get offsetY() {
1039
+ return this.offset.y;
1040
+ }
1041
+ /** @readonly */
1042
+ get globalX() {
1043
+ return this.global.x;
1044
+ }
1045
+ /** @readonly */
1046
+ get globalY() {
1047
+ return this.global.y;
1048
+ }
1049
+ /**
1050
+ * The pointer coordinates in the renderer's screen. Alias for `screen.x`.
1051
+ * @readonly
1052
+ */
1053
+ get screenX() {
1054
+ return this.screen.x;
1055
+ }
1056
+ /**
1057
+ * The pointer coordinates in the renderer's screen. Alias for `screen.y`.
1058
+ * @readonly
1059
+ */
1060
+ get screenY() {
1061
+ return this.screen.y;
1062
+ }
1063
+ /**
1064
+ * Converts global coordinates into container-local coordinates.
1065
+ *
1066
+ * This method transforms coordinates from world space to a container's local space,
1067
+ * useful for precise positioning and hit testing.
1068
+ * @param container - The Container to get local coordinates for
1069
+ * @param point - Optional Point object to store the result. If not provided, a new Point will be created
1070
+ * @param globalPos - Optional custom global coordinates. If not provided, the event's global position is used
1071
+ * @returns The local coordinates as a Point object
1072
+ * @example
1073
+ * ```ts
1074
+ * // Basic usage - get local coordinates relative to a container
1075
+ * sprite.on('pointermove', (event: FederatedMouseEvent) => {
1076
+ * // Get position relative to the sprite
1077
+ * const localPos = event.getLocalPosition(sprite);
1078
+ * console.log('Local position:', localPos.x, localPos.y);
1079
+ * });
1080
+ * // Using custom global coordinates
1081
+ * const customGlobal = new Point(100, 100);
1082
+ * sprite.on('pointermove', (event: FederatedMouseEvent) => {
1083
+ * // Transform custom coordinates
1084
+ * const localPos = event.getLocalPosition(sprite, undefined, customGlobal);
1085
+ * console.log('Custom local position:', localPos.x, localPos.y);
1086
+ * });
1087
+ * ```
1088
+ * @see {@link Container.worldTransform} For the transformation matrix
1089
+ * @see {@link Point} For the point class used to store coordinates
1090
+ */
1091
+ getLocalPosition(container, point, globalPos) {
1092
+ return container.worldTransform.applyInverse(globalPos || this.global, point);
1093
+ }
1094
+ /**
1095
+ * Whether the modifier key was pressed when this event natively occurred.
1096
+ * @param key - The modifier key.
1097
+ */
1098
+ getModifierState(key) {
1099
+ return "getModifierState" in this.nativeEvent && this.nativeEvent.getModifierState(key);
1100
+ }
1101
+ /**
1102
+ * Not supported.
1103
+ * @param _typeArg
1104
+ * @param _canBubbleArg
1105
+ * @param _cancelableArg
1106
+ * @param _viewArg
1107
+ * @param _detailArg
1108
+ * @param _screenXArg
1109
+ * @param _screenYArg
1110
+ * @param _clientXArg
1111
+ * @param _clientYArg
1112
+ * @param _ctrlKeyArg
1113
+ * @param _altKeyArg
1114
+ * @param _shiftKeyArg
1115
+ * @param _metaKeyArg
1116
+ * @param _buttonArg
1117
+ * @param _relatedTargetArg
1118
+ * @deprecated since 7.0.0
1119
+ * @ignore
1120
+ */
1121
+ // eslint-disable-next-line max-params
1122
+ initMouseEvent(_typeArg, _canBubbleArg, _cancelableArg, _viewArg, _detailArg, _screenXArg, _screenYArg, _clientXArg, _clientYArg, _ctrlKeyArg, _altKeyArg, _shiftKeyArg, _metaKeyArg, _buttonArg, _relatedTargetArg) {
1123
+ throw new Error("Method not implemented.");
1124
+ }
1125
+ }
1126
+ class FederatedPointerEvent extends FederatedMouseEvent {
1127
+ constructor() {
1128
+ super(...arguments);
1129
+ this.width = 0;
1130
+ this.height = 0;
1131
+ this.isPrimary = false;
1132
+ }
1133
+ /**
1134
+ * Only included for completeness for now
1135
+ * @ignore
1136
+ */
1137
+ getCoalescedEvents() {
1138
+ if (this.type === "pointermove" || this.type === "mousemove" || this.type === "touchmove") {
1139
+ return [this];
1140
+ }
1141
+ return [];
1142
+ }
1143
+ /**
1144
+ * Only included for completeness for now
1145
+ * @ignore
1146
+ */
1147
+ getPredictedEvents() {
1148
+ throw new Error("getPredictedEvents is not supported!");
1149
+ }
1150
+ }
1151
+ class FederatedWheelEvent extends FederatedMouseEvent {
1152
+ constructor() {
1153
+ super(...arguments);
1154
+ this.DOM_DELTA_PIXEL = 0;
1155
+ this.DOM_DELTA_LINE = 1;
1156
+ this.DOM_DELTA_PAGE = 2;
1157
+ }
1158
+ }
1159
+ FederatedWheelEvent.DOM_DELTA_PIXEL = 0;
1160
+ FederatedWheelEvent.DOM_DELTA_LINE = 1;
1161
+ FederatedWheelEvent.DOM_DELTA_PAGE = 2;
1162
+ const PROPAGATION_LIMIT = 2048;
1163
+ const tempHitLocation = new Point();
1164
+ const tempLocalMapping = new Point();
1165
+ class EventBoundary {
1166
+ /**
1167
+ * @param rootTarget - The holder of the event boundary.
1168
+ */
1169
+ constructor(rootTarget) {
1170
+ this.dispatch = new EventEmitter();
1171
+ this.moveOnAll = false;
1172
+ this.enableGlobalMoveEvents = true;
1173
+ this.mappingState = {
1174
+ trackingData: {}
1175
+ };
1176
+ this.eventPool = /* @__PURE__ */ new Map();
1177
+ this._allInteractiveElements = [];
1178
+ this._hitElements = [];
1179
+ this._isPointerMoveEvent = false;
1180
+ this.rootTarget = rootTarget;
1181
+ this.hitPruneFn = this.hitPruneFn.bind(this);
1182
+ this.hitTestFn = this.hitTestFn.bind(this);
1183
+ this.mapPointerDown = this.mapPointerDown.bind(this);
1184
+ this.mapPointerMove = this.mapPointerMove.bind(this);
1185
+ this.mapPointerOut = this.mapPointerOut.bind(this);
1186
+ this.mapPointerOver = this.mapPointerOver.bind(this);
1187
+ this.mapPointerUp = this.mapPointerUp.bind(this);
1188
+ this.mapPointerUpOutside = this.mapPointerUpOutside.bind(this);
1189
+ this.mapWheel = this.mapWheel.bind(this);
1190
+ this.mappingTable = {};
1191
+ this.addEventMapping("pointerdown", this.mapPointerDown);
1192
+ this.addEventMapping("pointermove", this.mapPointerMove);
1193
+ this.addEventMapping("pointerout", this.mapPointerOut);
1194
+ this.addEventMapping("pointerleave", this.mapPointerOut);
1195
+ this.addEventMapping("pointerover", this.mapPointerOver);
1196
+ this.addEventMapping("pointerup", this.mapPointerUp);
1197
+ this.addEventMapping("pointerupoutside", this.mapPointerUpOutside);
1198
+ this.addEventMapping("wheel", this.mapWheel);
1199
+ }
1200
+ /**
1201
+ * Adds an event mapping for the event `type` handled by `fn`.
1202
+ *
1203
+ * Event mappings can be used to implement additional or custom events. They take an event
1204
+ * coming from the upstream scene (or directly from the {@link EventSystem}) and dispatch new downstream events
1205
+ * generally trickling down and bubbling up to {@link EventBoundary.rootTarget this.rootTarget}.
1206
+ *
1207
+ * To modify the semantics of existing events, the built-in mapping methods of EventBoundary should be overridden
1208
+ * instead.
1209
+ * @param type - The type of upstream event to map.
1210
+ * @param fn - The mapping method. The context of this function must be bound manually, if desired.
1211
+ */
1212
+ addEventMapping(type, fn) {
1213
+ if (!this.mappingTable[type]) {
1214
+ this.mappingTable[type] = [];
1215
+ }
1216
+ this.mappingTable[type].push({
1217
+ fn,
1218
+ priority: 0
1219
+ });
1220
+ this.mappingTable[type].sort((a, b) => a.priority - b.priority);
1221
+ }
1222
+ /**
1223
+ * Dispatches the given event
1224
+ * @param e - The event to dispatch.
1225
+ * @param type - The type of event to dispatch. Defaults to `e.type`.
1226
+ */
1227
+ dispatchEvent(e, type) {
1228
+ e.propagationStopped = false;
1229
+ e.propagationImmediatelyStopped = false;
1230
+ this.propagate(e, type);
1231
+ this.dispatch.emit(type || e.type, e);
1232
+ }
1233
+ /**
1234
+ * Maps the given upstream event through the event boundary and propagates it downstream.
1235
+ * @param e - The event to map.
1236
+ */
1237
+ mapEvent(e) {
1238
+ if (!this.rootTarget) {
1239
+ return;
1240
+ }
1241
+ const mappers = this.mappingTable[e.type];
1242
+ if (mappers) {
1243
+ for (let i = 0, j = mappers.length; i < j; i++) {
1244
+ mappers[i].fn(e);
1245
+ }
1246
+ } else {
1247
+ warn(`[EventBoundary]: Event mapping not defined for ${e.type}`);
1248
+ }
1249
+ }
1250
+ /**
1251
+ * Finds the Container that is the target of a event at the given coordinates.
1252
+ *
1253
+ * The passed (x,y) coordinates are in the world space above this event boundary.
1254
+ * @param x - The x coordinate of the event.
1255
+ * @param y - The y coordinate of the event.
1256
+ */
1257
+ hitTest(x, y) {
1258
+ EventsTicker.pauseUpdate = true;
1259
+ const useMove = this._isPointerMoveEvent && this.enableGlobalMoveEvents;
1260
+ const fn = useMove ? "hitTestMoveRecursive" : "hitTestRecursive";
1261
+ const invertedPath = this[fn](
1262
+ this.rootTarget,
1263
+ this.rootTarget.eventMode,
1264
+ tempHitLocation.set(x, y),
1265
+ this.hitTestFn,
1266
+ this.hitPruneFn
1267
+ );
1268
+ return invertedPath && invertedPath[0];
1269
+ }
1270
+ /**
1271
+ * Propagate the passed event from from {@link EventBoundary.rootTarget this.rootTarget} to its
1272
+ * target `e.target`.
1273
+ * @param e - The event to propagate.
1274
+ * @param type - The type of event to propagate. Defaults to `e.type`.
1275
+ */
1276
+ propagate(e, type) {
1277
+ if (!e.target) {
1278
+ return;
1279
+ }
1280
+ const composedPath = e.composedPath();
1281
+ e.eventPhase = e.CAPTURING_PHASE;
1282
+ for (let i = 0, j = composedPath.length - 1; i < j; i++) {
1283
+ e.currentTarget = composedPath[i];
1284
+ this.notifyTarget(e, type);
1285
+ if (e.propagationStopped || e.propagationImmediatelyStopped) return;
1286
+ }
1287
+ e.eventPhase = e.AT_TARGET;
1288
+ e.currentTarget = e.target;
1289
+ this.notifyTarget(e, type);
1290
+ if (e.propagationStopped || e.propagationImmediatelyStopped) return;
1291
+ e.eventPhase = e.BUBBLING_PHASE;
1292
+ for (let i = composedPath.length - 2; i >= 0; i--) {
1293
+ e.currentTarget = composedPath[i];
1294
+ this.notifyTarget(e, type);
1295
+ if (e.propagationStopped || e.propagationImmediatelyStopped) return;
1296
+ }
1297
+ }
1298
+ /**
1299
+ * Emits the event `e` to all interactive containers. The event is propagated in the bubbling phase always.
1300
+ *
1301
+ * This is used in the `globalpointermove` event.
1302
+ * @param e - The emitted event.
1303
+ * @param type - The listeners to notify.
1304
+ * @param targets - The targets to notify.
1305
+ */
1306
+ all(e, type, targets = this._allInteractiveElements) {
1307
+ if (targets.length === 0) return;
1308
+ e.eventPhase = e.BUBBLING_PHASE;
1309
+ const events = Array.isArray(type) ? type : [type];
1310
+ for (let i = targets.length - 1; i >= 0; i--) {
1311
+ events.forEach((event) => {
1312
+ e.currentTarget = targets[i];
1313
+ this.notifyTarget(e, event);
1314
+ });
1315
+ }
1316
+ }
1317
+ /**
1318
+ * Finds the propagation path from {@link EventBoundary.rootTarget rootTarget} to the passed
1319
+ * `target`. The last element in the path is `target`.
1320
+ * @param target - The target to find the propagation path to.
1321
+ */
1322
+ propagationPath(target) {
1323
+ const propagationPath = [target];
1324
+ for (let i = 0; i < PROPAGATION_LIMIT && (target !== this.rootTarget && target.parent); i++) {
1325
+ if (!target.parent) {
1326
+ throw new Error("Cannot find propagation path to disconnected target");
1327
+ }
1328
+ propagationPath.push(target.parent);
1329
+ target = target.parent;
1330
+ }
1331
+ propagationPath.reverse();
1332
+ return propagationPath;
1333
+ }
1334
+ hitTestMoveRecursive(currentTarget, eventMode, location, testFn, pruneFn, ignore = false) {
1335
+ let shouldReturn = false;
1336
+ if (this._interactivePrune(currentTarget)) return null;
1337
+ if (currentTarget.eventMode === "dynamic" || eventMode === "dynamic") {
1338
+ EventsTicker.pauseUpdate = false;
1339
+ }
1340
+ if (currentTarget.interactiveChildren && currentTarget.children) {
1341
+ const children = currentTarget.children;
1342
+ for (let i = children.length - 1; i >= 0; i--) {
1343
+ const child = children[i];
1344
+ const nestedHit = this.hitTestMoveRecursive(
1345
+ child,
1346
+ this._isInteractive(eventMode) ? eventMode : child.eventMode,
1347
+ location,
1348
+ testFn,
1349
+ pruneFn,
1350
+ ignore || pruneFn(currentTarget, location)
1351
+ );
1352
+ if (nestedHit) {
1353
+ if (nestedHit.length > 0 && !nestedHit[nestedHit.length - 1].parent) {
1354
+ continue;
1355
+ }
1356
+ const isInteractive = currentTarget.isInteractive();
1357
+ if (nestedHit.length > 0 || isInteractive) {
1358
+ if (isInteractive) this._allInteractiveElements.push(currentTarget);
1359
+ nestedHit.push(currentTarget);
1360
+ }
1361
+ if (this._hitElements.length === 0) this._hitElements = nestedHit;
1362
+ shouldReturn = true;
1363
+ }
1364
+ }
1365
+ }
1366
+ const isInteractiveMode = this._isInteractive(eventMode);
1367
+ const isInteractiveTarget = currentTarget.isInteractive();
1368
+ if (isInteractiveTarget && isInteractiveTarget) this._allInteractiveElements.push(currentTarget);
1369
+ if (ignore || this._hitElements.length > 0) return null;
1370
+ if (shouldReturn) return this._hitElements;
1371
+ if (isInteractiveMode && (!pruneFn(currentTarget, location) && testFn(currentTarget, location))) {
1372
+ return isInteractiveTarget ? [currentTarget] : [];
1373
+ }
1374
+ return null;
1375
+ }
1376
+ /**
1377
+ * Recursive implementation for {@link EventBoundary.hitTest hitTest}.
1378
+ * @param currentTarget - The Container that is to be hit tested.
1379
+ * @param eventMode - The event mode for the `currentTarget` or one of its parents.
1380
+ * @param location - The location that is being tested for overlap.
1381
+ * @param testFn - Callback that determines whether the target passes hit testing. This callback
1382
+ * can assume that `pruneFn` failed to prune the container.
1383
+ * @param pruneFn - Callback that determiness whether the target and all of its children
1384
+ * cannot pass the hit test. It is used as a preliminary optimization to prune entire subtrees
1385
+ * of the scene graph.
1386
+ * @returns An array holding the hit testing target and all its ancestors in order. The first element
1387
+ * is the target itself and the last is {@link EventBoundary.rootTarget rootTarget}. This is the opposite
1388
+ * order w.r.t. the propagation path. If no hit testing target is found, null is returned.
1389
+ */
1390
+ hitTestRecursive(currentTarget, eventMode, location, testFn, pruneFn) {
1391
+ if (this._interactivePrune(currentTarget) || pruneFn(currentTarget, location)) {
1392
+ return null;
1393
+ }
1394
+ if (currentTarget.eventMode === "dynamic" || eventMode === "dynamic") {
1395
+ EventsTicker.pauseUpdate = false;
1396
+ }
1397
+ if (currentTarget.interactiveChildren && currentTarget.children) {
1398
+ const children = currentTarget.children;
1399
+ const relativeLocation = location;
1400
+ for (let i = children.length - 1; i >= 0; i--) {
1401
+ const child = children[i];
1402
+ const nestedHit = this.hitTestRecursive(
1403
+ child,
1404
+ this._isInteractive(eventMode) ? eventMode : child.eventMode,
1405
+ relativeLocation,
1406
+ testFn,
1407
+ pruneFn
1408
+ );
1409
+ if (nestedHit) {
1410
+ if (nestedHit.length > 0 && !nestedHit[nestedHit.length - 1].parent) {
1411
+ continue;
1412
+ }
1413
+ const isInteractive = currentTarget.isInteractive();
1414
+ if (nestedHit.length > 0 || isInteractive) nestedHit.push(currentTarget);
1415
+ return nestedHit;
1416
+ }
1417
+ }
1418
+ }
1419
+ const isInteractiveMode = this._isInteractive(eventMode);
1420
+ const isInteractiveTarget = currentTarget.isInteractive();
1421
+ if (isInteractiveMode && testFn(currentTarget, location)) {
1422
+ return isInteractiveTarget ? [currentTarget] : [];
1423
+ }
1424
+ return null;
1425
+ }
1426
+ _isInteractive(int) {
1427
+ return int === "static" || int === "dynamic";
1428
+ }
1429
+ _interactivePrune(container) {
1430
+ if (!container || !container.visible || !container.renderable || !container.measurable) {
1431
+ return true;
1432
+ }
1433
+ if (container.eventMode === "none") {
1434
+ return true;
1435
+ }
1436
+ if (container.eventMode === "passive" && !container.interactiveChildren) {
1437
+ return true;
1438
+ }
1439
+ return false;
1440
+ }
1441
+ /**
1442
+ * Checks whether the container or any of its children cannot pass the hit test at all.
1443
+ *
1444
+ * {@link EventBoundary}'s implementation uses the {@link Container.hitArea hitArea}
1445
+ * and {@link Container._maskEffect} for pruning.
1446
+ * @param container - The container to prune.
1447
+ * @param location - The location to test for overlap.
1448
+ */
1449
+ hitPruneFn(container, location) {
1450
+ if (container.hitArea) {
1451
+ container.worldTransform.applyInverse(location, tempLocalMapping);
1452
+ if (!container.hitArea.contains(tempLocalMapping.x, tempLocalMapping.y)) {
1453
+ return true;
1454
+ }
1455
+ }
1456
+ if (container.effects && container.effects.length) {
1457
+ for (let i = 0; i < container.effects.length; i++) {
1458
+ const effect = container.effects[i];
1459
+ if (effect.containsPoint) {
1460
+ const effectContainsPoint = effect.containsPoint(location, this.hitTestFn);
1461
+ if (!effectContainsPoint) {
1462
+ return true;
1463
+ }
1464
+ }
1465
+ }
1466
+ }
1467
+ return false;
1468
+ }
1469
+ /**
1470
+ * Checks whether the container passes hit testing for the given location.
1471
+ * @param container - The container to test.
1472
+ * @param location - The location to test for overlap.
1473
+ * @returns - Whether `container` passes hit testing for `location`.
1474
+ */
1475
+ hitTestFn(container, location) {
1476
+ if (container.hitArea) {
1477
+ return true;
1478
+ }
1479
+ if (container?.containsPoint) {
1480
+ container.worldTransform.applyInverse(location, tempLocalMapping);
1481
+ return container.containsPoint(tempLocalMapping);
1482
+ }
1483
+ return false;
1484
+ }
1485
+ /**
1486
+ * Notify all the listeners to the event's `currentTarget`.
1487
+ *
1488
+ * If the `currentTarget` contains the property `on<type>`, then it is called here,
1489
+ * simulating the behavior from version 6.x and prior.
1490
+ * @param e - The event passed to the target.
1491
+ * @param type - The type of event to notify. Defaults to `e.type`.
1492
+ */
1493
+ notifyTarget(e, type) {
1494
+ if (!e.currentTarget.isInteractive()) {
1495
+ return;
1496
+ }
1497
+ type ?? (type = e.type);
1498
+ const handlerKey = `on${type}`;
1499
+ e.currentTarget[handlerKey]?.(e);
1500
+ const key = e.eventPhase === e.CAPTURING_PHASE || e.eventPhase === e.AT_TARGET ? `${type}capture` : type;
1501
+ this._notifyListeners(e, key);
1502
+ if (e.eventPhase === e.AT_TARGET) {
1503
+ this._notifyListeners(e, type);
1504
+ }
1505
+ }
1506
+ /**
1507
+ * Maps the upstream `pointerdown` events to a downstream `pointerdown` event.
1508
+ *
1509
+ * `touchstart`, `rightdown`, `mousedown` events are also dispatched for specific pointer types.
1510
+ * @param from - The upstream `pointerdown` event.
1511
+ */
1512
+ mapPointerDown(from) {
1513
+ if (!(from instanceof FederatedPointerEvent)) {
1514
+ warn("EventBoundary cannot map a non-pointer event as a pointer event");
1515
+ return;
1516
+ }
1517
+ const e = this.createPointerEvent(from);
1518
+ this.dispatchEvent(e, "pointerdown");
1519
+ if (e.pointerType === "touch") {
1520
+ this.dispatchEvent(e, "touchstart");
1521
+ } else if (e.pointerType === "mouse" || e.pointerType === "pen") {
1522
+ const isRightButton = e.button === 2;
1523
+ this.dispatchEvent(e, isRightButton ? "rightdown" : "mousedown");
1524
+ }
1525
+ const trackingData = this.trackingData(from.pointerId);
1526
+ trackingData.pressTargetsByButton[from.button] = e.composedPath();
1527
+ this.freeEvent(e);
1528
+ }
1529
+ /**
1530
+ * Maps the upstream `pointermove` to downstream `pointerout`, `pointerover`, and `pointermove` events, in that order.
1531
+ *
1532
+ * The tracking data for the specific pointer has an updated `overTarget`. `mouseout`, `mouseover`,
1533
+ * `mousemove`, and `touchmove` events are fired as well for specific pointer types.
1534
+ * @param from - The upstream `pointermove` event.
1535
+ */
1536
+ mapPointerMove(from) {
1537
+ if (!(from instanceof FederatedPointerEvent)) {
1538
+ warn("EventBoundary cannot map a non-pointer event as a pointer event");
1539
+ return;
1540
+ }
1541
+ this._allInteractiveElements.length = 0;
1542
+ this._hitElements.length = 0;
1543
+ this._isPointerMoveEvent = true;
1544
+ const e = this.createPointerEvent(from);
1545
+ this._isPointerMoveEvent = false;
1546
+ const isMouse = e.pointerType === "mouse" || e.pointerType === "pen";
1547
+ const trackingData = this.trackingData(from.pointerId);
1548
+ const outTarget = this.findMountedTarget(trackingData.overTargets);
1549
+ if (trackingData.overTargets?.length > 0 && outTarget !== e.target) {
1550
+ const outType = from.type === "mousemove" ? "mouseout" : "pointerout";
1551
+ const outEvent = this.createPointerEvent(from, outType, outTarget);
1552
+ this.dispatchEvent(outEvent, "pointerout");
1553
+ if (isMouse) this.dispatchEvent(outEvent, "mouseout");
1554
+ if (!e.composedPath().includes(outTarget)) {
1555
+ const leaveEvent = this.createPointerEvent(from, "pointerleave", outTarget);
1556
+ leaveEvent.eventPhase = leaveEvent.AT_TARGET;
1557
+ while (leaveEvent.target && !e.composedPath().includes(leaveEvent.target)) {
1558
+ leaveEvent.currentTarget = leaveEvent.target;
1559
+ this.notifyTarget(leaveEvent);
1560
+ if (isMouse) this.notifyTarget(leaveEvent, "mouseleave");
1561
+ leaveEvent.target = leaveEvent.target.parent;
1562
+ }
1563
+ this.freeEvent(leaveEvent);
1564
+ }
1565
+ this.freeEvent(outEvent);
1566
+ }
1567
+ if (outTarget !== e.target) {
1568
+ const overType = from.type === "mousemove" ? "mouseover" : "pointerover";
1569
+ const overEvent = this.clonePointerEvent(e, overType);
1570
+ this.dispatchEvent(overEvent, "pointerover");
1571
+ if (isMouse) this.dispatchEvent(overEvent, "mouseover");
1572
+ let overTargetAncestor = outTarget?.parent;
1573
+ while (overTargetAncestor && overTargetAncestor !== this.rootTarget.parent) {
1574
+ if (overTargetAncestor === e.target) break;
1575
+ overTargetAncestor = overTargetAncestor.parent;
1576
+ }
1577
+ const didPointerEnter = !overTargetAncestor || overTargetAncestor === this.rootTarget.parent;
1578
+ if (didPointerEnter) {
1579
+ const enterEvent = this.clonePointerEvent(e, "pointerenter");
1580
+ enterEvent.eventPhase = enterEvent.AT_TARGET;
1581
+ while (enterEvent.target && enterEvent.target !== outTarget && enterEvent.target !== this.rootTarget.parent) {
1582
+ enterEvent.currentTarget = enterEvent.target;
1583
+ this.notifyTarget(enterEvent);
1584
+ if (isMouse) this.notifyTarget(enterEvent, "mouseenter");
1585
+ enterEvent.target = enterEvent.target.parent;
1586
+ }
1587
+ this.freeEvent(enterEvent);
1588
+ }
1589
+ this.freeEvent(overEvent);
1590
+ }
1591
+ const allMethods = [];
1592
+ const allowGlobalPointerEvents = this.enableGlobalMoveEvents ?? true;
1593
+ this.moveOnAll ? allMethods.push("pointermove") : this.dispatchEvent(e, "pointermove");
1594
+ allowGlobalPointerEvents && allMethods.push("globalpointermove");
1595
+ if (e.pointerType === "touch") {
1596
+ this.moveOnAll ? allMethods.splice(1, 0, "touchmove") : this.dispatchEvent(e, "touchmove");
1597
+ allowGlobalPointerEvents && allMethods.push("globaltouchmove");
1598
+ }
1599
+ if (isMouse) {
1600
+ this.moveOnAll ? allMethods.splice(1, 0, "mousemove") : this.dispatchEvent(e, "mousemove");
1601
+ allowGlobalPointerEvents && allMethods.push("globalmousemove");
1602
+ this.cursor = e.target?.cursor;
1603
+ }
1604
+ if (allMethods.length > 0) {
1605
+ this.all(e, allMethods);
1606
+ }
1607
+ this._allInteractiveElements.length = 0;
1608
+ this._hitElements.length = 0;
1609
+ trackingData.overTargets = e.composedPath();
1610
+ this.freeEvent(e);
1611
+ }
1612
+ /**
1613
+ * Maps the upstream `pointerover` to downstream `pointerover` and `pointerenter` events, in that order.
1614
+ *
1615
+ * The tracking data for the specific pointer gets a new `overTarget`.
1616
+ * @param from - The upstream `pointerover` event.
1617
+ */
1618
+ mapPointerOver(from) {
1619
+ if (!(from instanceof FederatedPointerEvent)) {
1620
+ warn("EventBoundary cannot map a non-pointer event as a pointer event");
1621
+ return;
1622
+ }
1623
+ const trackingData = this.trackingData(from.pointerId);
1624
+ const e = this.createPointerEvent(from);
1625
+ const isMouse = e.pointerType === "mouse" || e.pointerType === "pen";
1626
+ this.dispatchEvent(e, "pointerover");
1627
+ if (isMouse) this.dispatchEvent(e, "mouseover");
1628
+ if (e.pointerType === "mouse") this.cursor = e.target?.cursor;
1629
+ const enterEvent = this.clonePointerEvent(e, "pointerenter");
1630
+ enterEvent.eventPhase = enterEvent.AT_TARGET;
1631
+ while (enterEvent.target && enterEvent.target !== this.rootTarget.parent) {
1632
+ enterEvent.currentTarget = enterEvent.target;
1633
+ this.notifyTarget(enterEvent);
1634
+ if (isMouse) this.notifyTarget(enterEvent, "mouseenter");
1635
+ enterEvent.target = enterEvent.target.parent;
1636
+ }
1637
+ trackingData.overTargets = e.composedPath();
1638
+ this.freeEvent(e);
1639
+ this.freeEvent(enterEvent);
1640
+ }
1641
+ /**
1642
+ * Maps the upstream `pointerout` to downstream `pointerout`, `pointerleave` events, in that order.
1643
+ *
1644
+ * The tracking data for the specific pointer is cleared of a `overTarget`.
1645
+ * @param from - The upstream `pointerout` event.
1646
+ */
1647
+ mapPointerOut(from) {
1648
+ if (!(from instanceof FederatedPointerEvent)) {
1649
+ warn("EventBoundary cannot map a non-pointer event as a pointer event");
1650
+ return;
1651
+ }
1652
+ const trackingData = this.trackingData(from.pointerId);
1653
+ if (trackingData.overTargets) {
1654
+ const isMouse = from.pointerType === "mouse" || from.pointerType === "pen";
1655
+ const outTarget = this.findMountedTarget(trackingData.overTargets);
1656
+ const outEvent = this.createPointerEvent(from, "pointerout", outTarget);
1657
+ this.dispatchEvent(outEvent);
1658
+ if (isMouse) this.dispatchEvent(outEvent, "mouseout");
1659
+ const leaveEvent = this.createPointerEvent(from, "pointerleave", outTarget);
1660
+ leaveEvent.eventPhase = leaveEvent.AT_TARGET;
1661
+ while (leaveEvent.target && leaveEvent.target !== this.rootTarget.parent) {
1662
+ leaveEvent.currentTarget = leaveEvent.target;
1663
+ this.notifyTarget(leaveEvent);
1664
+ if (isMouse) this.notifyTarget(leaveEvent, "mouseleave");
1665
+ leaveEvent.target = leaveEvent.target.parent;
1666
+ }
1667
+ trackingData.overTargets = null;
1668
+ this.freeEvent(outEvent);
1669
+ this.freeEvent(leaveEvent);
1670
+ }
1671
+ this.cursor = null;
1672
+ }
1673
+ /**
1674
+ * Maps the upstream `pointerup` event to downstream `pointerup`, `pointerupoutside`,
1675
+ * and `click`/`rightclick`/`pointertap` events, in that order.
1676
+ *
1677
+ * The `pointerupoutside` event bubbles from the original `pointerdown` target to the most specific
1678
+ * ancestor of the `pointerdown` and `pointerup` targets, which is also the `click` event's target. `touchend`,
1679
+ * `rightup`, `mouseup`, `touchendoutside`, `rightupoutside`, `mouseupoutside`, and `tap` are fired as well for
1680
+ * specific pointer types.
1681
+ * @param from - The upstream `pointerup` event.
1682
+ */
1683
+ mapPointerUp(from) {
1684
+ if (!(from instanceof FederatedPointerEvent)) {
1685
+ warn("EventBoundary cannot map a non-pointer event as a pointer event");
1686
+ return;
1687
+ }
1688
+ const now = performance.now();
1689
+ const e = this.createPointerEvent(from);
1690
+ this.dispatchEvent(e, "pointerup");
1691
+ if (e.pointerType === "touch") {
1692
+ this.dispatchEvent(e, "touchend");
1693
+ } else if (e.pointerType === "mouse" || e.pointerType === "pen") {
1694
+ const isRightButton = e.button === 2;
1695
+ this.dispatchEvent(e, isRightButton ? "rightup" : "mouseup");
1696
+ }
1697
+ const trackingData = this.trackingData(from.pointerId);
1698
+ const pressTarget = this.findMountedTarget(trackingData.pressTargetsByButton[from.button]);
1699
+ let clickTarget = pressTarget;
1700
+ if (pressTarget && !e.composedPath().includes(pressTarget)) {
1701
+ let currentTarget = pressTarget;
1702
+ while (currentTarget && !e.composedPath().includes(currentTarget)) {
1703
+ e.currentTarget = currentTarget;
1704
+ this.notifyTarget(e, "pointerupoutside");
1705
+ if (e.pointerType === "touch") {
1706
+ this.notifyTarget(e, "touchendoutside");
1707
+ } else if (e.pointerType === "mouse" || e.pointerType === "pen") {
1708
+ const isRightButton = e.button === 2;
1709
+ this.notifyTarget(e, isRightButton ? "rightupoutside" : "mouseupoutside");
1710
+ }
1711
+ currentTarget = currentTarget.parent;
1712
+ }
1713
+ delete trackingData.pressTargetsByButton[from.button];
1714
+ clickTarget = currentTarget;
1715
+ }
1716
+ if (clickTarget) {
1717
+ const clickEvent = this.clonePointerEvent(e, "click");
1718
+ clickEvent.target = clickTarget;
1719
+ clickEvent.path = null;
1720
+ if (!trackingData.clicksByButton[from.button]) {
1721
+ trackingData.clicksByButton[from.button] = {
1722
+ clickCount: 0,
1723
+ target: clickEvent.target,
1724
+ timeStamp: now
1725
+ };
1726
+ }
1727
+ const clickHistory = trackingData.clicksByButton[from.button];
1728
+ if (clickHistory.target === clickEvent.target && now - clickHistory.timeStamp < 200) {
1729
+ ++clickHistory.clickCount;
1730
+ } else {
1731
+ clickHistory.clickCount = 1;
1732
+ }
1733
+ clickHistory.target = clickEvent.target;
1734
+ clickHistory.timeStamp = now;
1735
+ clickEvent.detail = clickHistory.clickCount;
1736
+ if (clickEvent.pointerType === "mouse") {
1737
+ const isRightButton = clickEvent.button === 2;
1738
+ this.dispatchEvent(clickEvent, isRightButton ? "rightclick" : "click");
1739
+ } else if (clickEvent.pointerType === "touch") {
1740
+ this.dispatchEvent(clickEvent, "tap");
1741
+ }
1742
+ this.dispatchEvent(clickEvent, "pointertap");
1743
+ this.freeEvent(clickEvent);
1744
+ }
1745
+ this.freeEvent(e);
1746
+ }
1747
+ /**
1748
+ * Maps the upstream `pointerupoutside` event to a downstream `pointerupoutside` event, bubbling from the original
1749
+ * `pointerdown` target to `rootTarget`.
1750
+ *
1751
+ * (The most specific ancestor of the `pointerdown` event and the `pointerup` event must the
1752
+ * `{@link EventBoundary}'s root because the `pointerup` event occurred outside of the boundary.)
1753
+ *
1754
+ * `touchendoutside`, `mouseupoutside`, and `rightupoutside` events are fired as well for specific pointer
1755
+ * types. The tracking data for the specific pointer is cleared of a `pressTarget`.
1756
+ * @param from - The upstream `pointerupoutside` event.
1757
+ */
1758
+ mapPointerUpOutside(from) {
1759
+ if (!(from instanceof FederatedPointerEvent)) {
1760
+ warn("EventBoundary cannot map a non-pointer event as a pointer event");
1761
+ return;
1762
+ }
1763
+ const trackingData = this.trackingData(from.pointerId);
1764
+ const pressTarget = this.findMountedTarget(trackingData.pressTargetsByButton[from.button]);
1765
+ const e = this.createPointerEvent(from);
1766
+ if (pressTarget) {
1767
+ let currentTarget = pressTarget;
1768
+ while (currentTarget) {
1769
+ e.currentTarget = currentTarget;
1770
+ this.notifyTarget(e, "pointerupoutside");
1771
+ if (e.pointerType === "touch") {
1772
+ this.notifyTarget(e, "touchendoutside");
1773
+ } else if (e.pointerType === "mouse" || e.pointerType === "pen") {
1774
+ this.notifyTarget(e, e.button === 2 ? "rightupoutside" : "mouseupoutside");
1775
+ }
1776
+ currentTarget = currentTarget.parent;
1777
+ }
1778
+ delete trackingData.pressTargetsByButton[from.button];
1779
+ }
1780
+ this.freeEvent(e);
1781
+ }
1782
+ /**
1783
+ * Maps the upstream `wheel` event to a downstream `wheel` event.
1784
+ * @param from - The upstream `wheel` event.
1785
+ */
1786
+ mapWheel(from) {
1787
+ if (!(from instanceof FederatedWheelEvent)) {
1788
+ warn("EventBoundary cannot map a non-wheel event as a wheel event");
1789
+ return;
1790
+ }
1791
+ const wheelEvent = this.createWheelEvent(from);
1792
+ this.dispatchEvent(wheelEvent);
1793
+ this.freeEvent(wheelEvent);
1794
+ }
1795
+ /**
1796
+ * Finds the most specific event-target in the given propagation path that is still mounted in the scene graph.
1797
+ *
1798
+ * This is used to find the correct `pointerup` and `pointerout` target in the case that the original `pointerdown`
1799
+ * or `pointerover` target was unmounted from the scene graph.
1800
+ * @param propagationPath - The propagation path was valid in the past.
1801
+ * @returns - The most specific event-target still mounted at the same location in the scene graph.
1802
+ */
1803
+ findMountedTarget(propagationPath) {
1804
+ if (!propagationPath) {
1805
+ return null;
1806
+ }
1807
+ let currentTarget = propagationPath[0];
1808
+ for (let i = 1; i < propagationPath.length; i++) {
1809
+ if (propagationPath[i].parent === currentTarget) {
1810
+ currentTarget = propagationPath[i];
1811
+ } else {
1812
+ break;
1813
+ }
1814
+ }
1815
+ return currentTarget;
1816
+ }
1817
+ /**
1818
+ * Creates an event whose `originalEvent` is `from`, with an optional `type` and `target` override.
1819
+ *
1820
+ * The event is allocated using {@link EventBoundary#allocateEvent this.allocateEvent}.
1821
+ * @param from - The `originalEvent` for the returned event.
1822
+ * @param [type=from.type] - The type of the returned event.
1823
+ * @param target - The target of the returned event.
1824
+ */
1825
+ createPointerEvent(from, type, target) {
1826
+ const event = this.allocateEvent(FederatedPointerEvent);
1827
+ this.copyPointerData(from, event);
1828
+ this.copyMouseData(from, event);
1829
+ this.copyData(from, event);
1830
+ event.nativeEvent = from.nativeEvent;
1831
+ event.originalEvent = from;
1832
+ event.target = target ?? this.hitTest(event.global.x, event.global.y) ?? this._hitElements[0];
1833
+ if (typeof type === "string") {
1834
+ event.type = type;
1835
+ }
1836
+ return event;
1837
+ }
1838
+ /**
1839
+ * Creates a wheel event whose `originalEvent` is `from`.
1840
+ *
1841
+ * The event is allocated using {@link EventBoundary#allocateEvent this.allocateEvent}.
1842
+ * @param from - The upstream wheel event.
1843
+ */
1844
+ createWheelEvent(from) {
1845
+ const event = this.allocateEvent(FederatedWheelEvent);
1846
+ this.copyWheelData(from, event);
1847
+ this.copyMouseData(from, event);
1848
+ this.copyData(from, event);
1849
+ event.nativeEvent = from.nativeEvent;
1850
+ event.originalEvent = from;
1851
+ event.target = this.hitTest(event.global.x, event.global.y);
1852
+ return event;
1853
+ }
1854
+ /**
1855
+ * Clones the event `from`, with an optional `type` override.
1856
+ *
1857
+ * The event is allocated using {@link EventBoundary#allocateEvent this.allocateEvent}.
1858
+ * @param from - The event to clone.
1859
+ * @param [type=from.type] - The type of the returned event.
1860
+ */
1861
+ clonePointerEvent(from, type) {
1862
+ const event = this.allocateEvent(FederatedPointerEvent);
1863
+ event.nativeEvent = from.nativeEvent;
1864
+ event.originalEvent = from.originalEvent;
1865
+ this.copyPointerData(from, event);
1866
+ this.copyMouseData(from, event);
1867
+ this.copyData(from, event);
1868
+ event.target = from.target;
1869
+ event.path = from.composedPath().slice();
1870
+ event.type = type ?? event.type;
1871
+ return event;
1872
+ }
1873
+ /**
1874
+ * Copies wheel {@link FederatedWheelEvent} data from `from` into `to`.
1875
+ *
1876
+ * The following properties are copied:
1877
+ * + deltaMode
1878
+ * + deltaX
1879
+ * + deltaY
1880
+ * + deltaZ
1881
+ * @param from - The event to copy data from.
1882
+ * @param to - The event to copy data into.
1883
+ */
1884
+ copyWheelData(from, to) {
1885
+ to.deltaMode = from.deltaMode;
1886
+ to.deltaX = from.deltaX;
1887
+ to.deltaY = from.deltaY;
1888
+ to.deltaZ = from.deltaZ;
1889
+ }
1890
+ /**
1891
+ * Copies pointer {@link FederatedPointerEvent} data from `from` into `to`.
1892
+ *
1893
+ * The following properties are copied:
1894
+ * + pointerId
1895
+ * + width
1896
+ * + height
1897
+ * + isPrimary
1898
+ * + pointerType
1899
+ * + pressure
1900
+ * + tangentialPressure
1901
+ * + tiltX
1902
+ * + tiltY
1903
+ * @param from - The event to copy data from.
1904
+ * @param to - The event to copy data into.
1905
+ */
1906
+ copyPointerData(from, to) {
1907
+ if (!(from instanceof FederatedPointerEvent && to instanceof FederatedPointerEvent)) return;
1908
+ to.pointerId = from.pointerId;
1909
+ to.width = from.width;
1910
+ to.height = from.height;
1911
+ to.isPrimary = from.isPrimary;
1912
+ to.pointerType = from.pointerType;
1913
+ to.pressure = from.pressure;
1914
+ to.tangentialPressure = from.tangentialPressure;
1915
+ to.tiltX = from.tiltX;
1916
+ to.tiltY = from.tiltY;
1917
+ to.twist = from.twist;
1918
+ }
1919
+ /**
1920
+ * Copies mouse {@link FederatedMouseEvent} data from `from` to `to`.
1921
+ *
1922
+ * The following properties are copied:
1923
+ * + altKey
1924
+ * + button
1925
+ * + buttons
1926
+ * + clientX
1927
+ * + clientY
1928
+ * + metaKey
1929
+ * + movementX
1930
+ * + movementY
1931
+ * + pageX
1932
+ * + pageY
1933
+ * + x
1934
+ * + y
1935
+ * + screen
1936
+ * + shiftKey
1937
+ * + global
1938
+ * @param from - The event to copy data from.
1939
+ * @param to - The event to copy data into.
1940
+ */
1941
+ copyMouseData(from, to) {
1942
+ if (!(from instanceof FederatedMouseEvent && to instanceof FederatedMouseEvent)) return;
1943
+ to.altKey = from.altKey;
1944
+ to.button = from.button;
1945
+ to.buttons = from.buttons;
1946
+ to.client.copyFrom(from.client);
1947
+ to.ctrlKey = from.ctrlKey;
1948
+ to.metaKey = from.metaKey;
1949
+ to.movement.copyFrom(from.movement);
1950
+ to.screen.copyFrom(from.screen);
1951
+ to.shiftKey = from.shiftKey;
1952
+ to.global.copyFrom(from.global);
1953
+ }
1954
+ /**
1955
+ * Copies base {@link FederatedEvent} data from `from` into `to`.
1956
+ *
1957
+ * The following properties are copied:
1958
+ * + isTrusted
1959
+ * + srcElement
1960
+ * + timeStamp
1961
+ * + type
1962
+ * @param from - The event to copy data from.
1963
+ * @param to - The event to copy data into.
1964
+ */
1965
+ copyData(from, to) {
1966
+ to.isTrusted = from.isTrusted;
1967
+ to.srcElement = from.srcElement;
1968
+ to.timeStamp = performance.now();
1969
+ to.type = from.type;
1970
+ to.detail = from.detail;
1971
+ to.view = from.view;
1972
+ to.which = from.which;
1973
+ to.layer.copyFrom(from.layer);
1974
+ to.page.copyFrom(from.page);
1975
+ }
1976
+ /**
1977
+ * @param id - The pointer ID.
1978
+ * @returns The tracking data stored for the given pointer. If no data exists, a blank
1979
+ * state will be created.
1980
+ */
1981
+ trackingData(id) {
1982
+ if (!this.mappingState.trackingData[id]) {
1983
+ this.mappingState.trackingData[id] = {
1984
+ pressTargetsByButton: {},
1985
+ clicksByButton: {},
1986
+ overTarget: null
1987
+ };
1988
+ }
1989
+ return this.mappingState.trackingData[id];
1990
+ }
1991
+ /**
1992
+ * Allocate a specific type of event from {@link EventBoundary#eventPool this.eventPool}.
1993
+ *
1994
+ * This allocation is constructor-agnostic, as long as it only takes one argument - this event
1995
+ * boundary.
1996
+ * @param constructor - The event's constructor.
1997
+ * @returns An event of the given type.
1998
+ */
1999
+ allocateEvent(constructor) {
2000
+ if (!this.eventPool.has(constructor)) {
2001
+ this.eventPool.set(constructor, []);
2002
+ }
2003
+ const event = this.eventPool.get(constructor).pop() || new constructor(this);
2004
+ event.eventPhase = event.NONE;
2005
+ event.currentTarget = null;
2006
+ event.defaultPrevented = false;
2007
+ event.path = null;
2008
+ event.target = null;
2009
+ return event;
2010
+ }
2011
+ /**
2012
+ * Frees the event and puts it back into the event pool.
2013
+ *
2014
+ * It is illegal to reuse the event until it is allocated again, using `this.allocateEvent`.
2015
+ *
2016
+ * It is also advised that events not allocated from {@link EventBoundary#allocateEvent this.allocateEvent}
2017
+ * not be freed. This is because of the possibility that the same event is freed twice, which can cause
2018
+ * it to be allocated twice & result in overwriting.
2019
+ * @param event - The event to be freed.
2020
+ * @throws Error if the event is managed by another event boundary.
2021
+ */
2022
+ freeEvent(event) {
2023
+ if (event.manager !== this) throw new Error("It is illegal to free an event not managed by this EventBoundary!");
2024
+ const constructor = event.constructor;
2025
+ if (!this.eventPool.has(constructor)) {
2026
+ this.eventPool.set(constructor, []);
2027
+ }
2028
+ this.eventPool.get(constructor).push(event);
2029
+ }
2030
+ /**
2031
+ * Similar to {@link EventEmitter.emit}, except it stops if the `propagationImmediatelyStopped` flag
2032
+ * is set on the event.
2033
+ * @param e - The event to call each listener with.
2034
+ * @param type - The event key.
2035
+ */
2036
+ _notifyListeners(e, type) {
2037
+ const listeners = e.currentTarget._events[type];
2038
+ if (!listeners) return;
2039
+ if ("fn" in listeners) {
2040
+ if (listeners.once) e.currentTarget.removeListener(type, listeners.fn, void 0, true);
2041
+ listeners.fn.call(listeners.context, e);
2042
+ } else {
2043
+ for (let i = 0, j = listeners.length; i < j && !e.propagationImmediatelyStopped; i++) {
2044
+ if (listeners[i].once) e.currentTarget.removeListener(type, listeners[i].fn, void 0, true);
2045
+ listeners[i].fn.call(listeners[i].context, e);
2046
+ }
2047
+ }
2048
+ }
2049
+ }
2050
+ const MOUSE_POINTER_ID = 1;
2051
+ const TOUCH_TO_POINTER = {
2052
+ touchstart: "pointerdown",
2053
+ touchend: "pointerup",
2054
+ touchendoutside: "pointerupoutside",
2055
+ touchmove: "pointermove",
2056
+ touchcancel: "pointercancel"
2057
+ };
2058
+ const _EventSystem = class _EventSystem2 {
2059
+ /**
2060
+ * @param {Renderer} renderer
2061
+ */
2062
+ constructor(renderer) {
2063
+ this.supportsTouchEvents = "ontouchstart" in globalThis;
2064
+ this.supportsPointerEvents = !!globalThis.PointerEvent;
2065
+ this.domElement = null;
2066
+ this.resolution = 1;
2067
+ this.renderer = renderer;
2068
+ this.rootBoundary = new EventBoundary(null);
2069
+ EventsTicker.init(this);
2070
+ this.autoPreventDefault = true;
2071
+ this._eventsAdded = false;
2072
+ this._rootPointerEvent = new FederatedPointerEvent(null);
2073
+ this._rootWheelEvent = new FederatedWheelEvent(null);
2074
+ this.cursorStyles = {
2075
+ default: "inherit",
2076
+ pointer: "pointer"
2077
+ };
2078
+ this.features = new Proxy({ ..._EventSystem2.defaultEventFeatures }, {
2079
+ set: (target, key, value) => {
2080
+ if (key === "globalMove") {
2081
+ this.rootBoundary.enableGlobalMoveEvents = value;
2082
+ }
2083
+ target[key] = value;
2084
+ return true;
2085
+ }
2086
+ });
2087
+ this._onPointerDown = this._onPointerDown.bind(this);
2088
+ this._onPointerMove = this._onPointerMove.bind(this);
2089
+ this._onPointerUp = this._onPointerUp.bind(this);
2090
+ this._onPointerOverOut = this._onPointerOverOut.bind(this);
2091
+ this.onWheel = this.onWheel.bind(this);
2092
+ }
2093
+ /**
2094
+ * The default interaction mode for all display objects.
2095
+ * @see Container.eventMode
2096
+ * @type {EventMode}
2097
+ * @readonly
2098
+ * @since 7.2.0
2099
+ */
2100
+ static get defaultEventMode() {
2101
+ return this._defaultEventMode;
2102
+ }
2103
+ /**
2104
+ * Runner init called, view is available at this point.
2105
+ * @ignore
2106
+ */
2107
+ init(options) {
2108
+ const { canvas, resolution } = this.renderer;
2109
+ this.setTargetElement(canvas);
2110
+ this.resolution = resolution;
2111
+ _EventSystem2._defaultEventMode = options.eventMode ?? "passive";
2112
+ Object.assign(this.features, options.eventFeatures ?? {});
2113
+ this.rootBoundary.enableGlobalMoveEvents = this.features.globalMove;
2114
+ }
2115
+ /**
2116
+ * Handle changing resolution.
2117
+ * @ignore
2118
+ */
2119
+ resolutionChange(resolution) {
2120
+ this.resolution = resolution;
2121
+ }
2122
+ /** Destroys all event listeners and detaches the renderer. */
2123
+ destroy() {
2124
+ EventsTicker.destroy();
2125
+ this.setTargetElement(null);
2126
+ this.renderer = null;
2127
+ this._currentCursor = null;
2128
+ }
2129
+ /**
2130
+ * Sets the current cursor mode, handling any callbacks or CSS style changes.
2131
+ * The cursor can be a CSS cursor string, a custom callback function, or a key from the cursorStyles dictionary.
2132
+ * @param mode - Cursor mode to set. Can be:
2133
+ * - A CSS cursor string (e.g., 'pointer', 'grab')
2134
+ * - A key from the cursorStyles dictionary
2135
+ * - null/undefined to reset to default
2136
+ * @example
2137
+ * ```ts
2138
+ * // Using predefined cursor styles
2139
+ * app.renderer.events.setCursor('pointer'); // Set standard pointer cursor
2140
+ * app.renderer.events.setCursor('grab'); // Set grab cursor
2141
+ * app.renderer.events.setCursor(null); // Reset to default
2142
+ *
2143
+ * // Using custom cursor styles
2144
+ * app.renderer.events.cursorStyles.custom = 'url("cursor.png"), auto';
2145
+ * app.renderer.events.setCursor('custom'); // Apply custom cursor
2146
+ *
2147
+ * // Using callback-based cursor
2148
+ * app.renderer.events.cursorStyles.dynamic = (mode) => {
2149
+ * document.body.style.cursor = mode === 'hover' ? 'pointer' : 'default';
2150
+ * };
2151
+ * app.renderer.events.setCursor('dynamic'); // Trigger cursor callback
2152
+ * ```
2153
+ * @remarks
2154
+ * - Has no effect on OffscreenCanvas except for callback-based cursors
2155
+ * - Caches current cursor to avoid unnecessary DOM updates
2156
+ * - Supports CSS cursor values, style objects, and callback functions
2157
+ * @see {@link EventSystem.cursorStyles} For defining custom cursor styles
2158
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/cursor} MDN Cursor Reference
2159
+ */
2160
+ setCursor(mode) {
2161
+ mode || (mode = "default");
2162
+ let applyStyles = true;
2163
+ if (globalThis.OffscreenCanvas && this.domElement instanceof OffscreenCanvas) {
2164
+ applyStyles = false;
2165
+ }
2166
+ if (this._currentCursor === mode) {
2167
+ return;
2168
+ }
2169
+ this._currentCursor = mode;
2170
+ const style = this.cursorStyles[mode];
2171
+ if (style) {
2172
+ switch (typeof style) {
2173
+ case "string":
2174
+ if (applyStyles) {
2175
+ this.domElement.style.cursor = style;
2176
+ }
2177
+ break;
2178
+ case "function":
2179
+ style(mode);
2180
+ break;
2181
+ case "object":
2182
+ if (applyStyles) {
2183
+ Object.assign(this.domElement.style, style);
2184
+ }
2185
+ break;
2186
+ }
2187
+ } else if (applyStyles && typeof mode === "string" && !Object.prototype.hasOwnProperty.call(this.cursorStyles, mode)) {
2188
+ this.domElement.style.cursor = mode;
2189
+ }
2190
+ }
2191
+ /**
2192
+ * The global pointer event instance containing the most recent pointer state.
2193
+ * This is useful for accessing pointer information without listening to events.
2194
+ * @example
2195
+ * ```ts
2196
+ * // Access current pointer position at any time
2197
+ * const eventSystem = app.renderer.events;
2198
+ * const pointer = eventSystem.pointer;
2199
+ *
2200
+ * // Get global coordinates
2201
+ * console.log('Position:', pointer.global.x, pointer.global.y);
2202
+ *
2203
+ * // Check button state
2204
+ * console.log('Buttons pressed:', pointer.buttons);
2205
+ *
2206
+ * // Get pointer type and pressure
2207
+ * console.log('Type:', pointer.pointerType);
2208
+ * console.log('Pressure:', pointer.pressure);
2209
+ * ```
2210
+ * @readonly
2211
+ * @since 7.2.0
2212
+ * @see {@link FederatedPointerEvent} For all available pointer properties
2213
+ */
2214
+ get pointer() {
2215
+ return this._rootPointerEvent;
2216
+ }
2217
+ /**
2218
+ * Event handler for pointer down events on {@link EventSystem#domElement this.domElement}.
2219
+ * @param nativeEvent - The native mouse/pointer/touch event.
2220
+ */
2221
+ _onPointerDown(nativeEvent) {
2222
+ if (!this.features.click) return;
2223
+ this.rootBoundary.rootTarget = this.renderer.lastObjectRendered;
2224
+ const events = this._normalizeToPointerData(nativeEvent);
2225
+ if (this.autoPreventDefault && events[0].isNormalized) {
2226
+ const cancelable = nativeEvent.cancelable || !("cancelable" in nativeEvent);
2227
+ if (cancelable) {
2228
+ nativeEvent.preventDefault();
2229
+ }
2230
+ }
2231
+ for (let i = 0, j = events.length; i < j; i++) {
2232
+ const nativeEvent2 = events[i];
2233
+ const federatedEvent = this._bootstrapEvent(this._rootPointerEvent, nativeEvent2);
2234
+ this.rootBoundary.mapEvent(federatedEvent);
2235
+ }
2236
+ this.setCursor(this.rootBoundary.cursor);
2237
+ }
2238
+ /**
2239
+ * Event handler for pointer move events on on {@link EventSystem#domElement this.domElement}.
2240
+ * @param nativeEvent - The native mouse/pointer/touch events.
2241
+ */
2242
+ _onPointerMove(nativeEvent) {
2243
+ if (!this.features.move) return;
2244
+ this.rootBoundary.rootTarget = this.renderer.lastObjectRendered;
2245
+ EventsTicker.pointerMoved();
2246
+ const normalizedEvents = this._normalizeToPointerData(nativeEvent);
2247
+ for (let i = 0, j = normalizedEvents.length; i < j; i++) {
2248
+ const event = this._bootstrapEvent(this._rootPointerEvent, normalizedEvents[i]);
2249
+ this.rootBoundary.mapEvent(event);
2250
+ }
2251
+ this.setCursor(this.rootBoundary.cursor);
2252
+ }
2253
+ /**
2254
+ * Event handler for pointer up events on {@link EventSystem#domElement this.domElement}.
2255
+ * @param nativeEvent - The native mouse/pointer/touch event.
2256
+ */
2257
+ _onPointerUp(nativeEvent) {
2258
+ if (!this.features.click) return;
2259
+ this.rootBoundary.rootTarget = this.renderer.lastObjectRendered;
2260
+ let target = nativeEvent.target;
2261
+ if (nativeEvent.composedPath && nativeEvent.composedPath().length > 0) {
2262
+ target = nativeEvent.composedPath()[0];
2263
+ }
2264
+ const outside = target !== this.domElement ? "outside" : "";
2265
+ const normalizedEvents = this._normalizeToPointerData(nativeEvent);
2266
+ for (let i = 0, j = normalizedEvents.length; i < j; i++) {
2267
+ const event = this._bootstrapEvent(this._rootPointerEvent, normalizedEvents[i]);
2268
+ event.type += outside;
2269
+ this.rootBoundary.mapEvent(event);
2270
+ }
2271
+ this.setCursor(this.rootBoundary.cursor);
2272
+ }
2273
+ /**
2274
+ * Event handler for pointer over & out events on {@link EventSystem#domElement this.domElement}.
2275
+ * @param nativeEvent - The native mouse/pointer/touch event.
2276
+ */
2277
+ _onPointerOverOut(nativeEvent) {
2278
+ if (!this.features.click) return;
2279
+ this.rootBoundary.rootTarget = this.renderer.lastObjectRendered;
2280
+ const normalizedEvents = this._normalizeToPointerData(nativeEvent);
2281
+ for (let i = 0, j = normalizedEvents.length; i < j; i++) {
2282
+ const event = this._bootstrapEvent(this._rootPointerEvent, normalizedEvents[i]);
2283
+ this.rootBoundary.mapEvent(event);
2284
+ }
2285
+ this.setCursor(this.rootBoundary.cursor);
2286
+ }
2287
+ /**
2288
+ * Passive handler for `wheel` events on {@link EventSystem.domElement this.domElement}.
2289
+ * @param nativeEvent - The native wheel event.
2290
+ */
2291
+ onWheel(nativeEvent) {
2292
+ if (!this.features.wheel) return;
2293
+ const wheelEvent = this.normalizeWheelEvent(nativeEvent);
2294
+ this.rootBoundary.rootTarget = this.renderer.lastObjectRendered;
2295
+ this.rootBoundary.mapEvent(wheelEvent);
2296
+ }
2297
+ /**
2298
+ * Sets the {@link EventSystem#domElement domElement} and binds event listeners.
2299
+ * This method manages the DOM event bindings for the event system, allowing you to
2300
+ * change or remove the target element that receives input events.
2301
+ * > [!IMPORTANT] This will default to the canvas element of the renderer, so you
2302
+ * > should not need to call this unless you are using a custom element.
2303
+ * @param element - The new DOM element to bind events to, or null to remove all event bindings
2304
+ * @example
2305
+ * ```ts
2306
+ * // Set a new canvas element as the target
2307
+ * const canvas = document.createElement('canvas');
2308
+ * app.renderer.events.setTargetElement(canvas);
2309
+ *
2310
+ * // Remove all event bindings
2311
+ * app.renderer.events.setTargetElement(null);
2312
+ *
2313
+ * // Switch to a different canvas
2314
+ * const newCanvas = document.querySelector('#game-canvas');
2315
+ * app.renderer.events.setTargetElement(newCanvas);
2316
+ * ```
2317
+ * @remarks
2318
+ * - Automatically removes event listeners from previous element
2319
+ * - Required for the event system to function
2320
+ * - Safe to call multiple times
2321
+ * @see {@link EventSystem#domElement} The current DOM element
2322
+ * @see {@link EventsTicker} For the ticker system that tracks pointer movement
2323
+ */
2324
+ setTargetElement(element) {
2325
+ this._removeEvents();
2326
+ this.domElement = element;
2327
+ EventsTicker.domElement = element;
2328
+ this._addEvents();
2329
+ }
2330
+ /** Register event listeners on {@link Renderer#domElement this.domElement}. */
2331
+ _addEvents() {
2332
+ if (this._eventsAdded || !this.domElement) {
2333
+ return;
2334
+ }
2335
+ EventsTicker.addTickerListener();
2336
+ const style = this.domElement.style;
2337
+ if (style) {
2338
+ if (globalThis.navigator.msPointerEnabled) {
2339
+ style.msContentZooming = "none";
2340
+ style.msTouchAction = "none";
2341
+ } else if (this.supportsPointerEvents) {
2342
+ style.touchAction = "none";
2343
+ }
2344
+ }
2345
+ if (this.supportsPointerEvents) {
2346
+ globalThis.document.addEventListener("pointermove", this._onPointerMove, true);
2347
+ this.domElement.addEventListener("pointerdown", this._onPointerDown, true);
2348
+ this.domElement.addEventListener("pointerleave", this._onPointerOverOut, true);
2349
+ this.domElement.addEventListener("pointerover", this._onPointerOverOut, true);
2350
+ globalThis.addEventListener("pointerup", this._onPointerUp, true);
2351
+ } else {
2352
+ globalThis.document.addEventListener("mousemove", this._onPointerMove, true);
2353
+ this.domElement.addEventListener("mousedown", this._onPointerDown, true);
2354
+ this.domElement.addEventListener("mouseout", this._onPointerOverOut, true);
2355
+ this.domElement.addEventListener("mouseover", this._onPointerOverOut, true);
2356
+ globalThis.addEventListener("mouseup", this._onPointerUp, true);
2357
+ if (this.supportsTouchEvents) {
2358
+ this.domElement.addEventListener("touchstart", this._onPointerDown, true);
2359
+ this.domElement.addEventListener("touchend", this._onPointerUp, true);
2360
+ this.domElement.addEventListener("touchmove", this._onPointerMove, true);
2361
+ }
2362
+ }
2363
+ this.domElement.addEventListener("wheel", this.onWheel, {
2364
+ passive: true,
2365
+ capture: true
2366
+ });
2367
+ this._eventsAdded = true;
2368
+ }
2369
+ /** Unregister event listeners on {@link EventSystem#domElement this.domElement}. */
2370
+ _removeEvents() {
2371
+ if (!this._eventsAdded || !this.domElement) {
2372
+ return;
2373
+ }
2374
+ EventsTicker.removeTickerListener();
2375
+ const style = this.domElement.style;
2376
+ if (style) {
2377
+ if (globalThis.navigator.msPointerEnabled) {
2378
+ style.msContentZooming = "";
2379
+ style.msTouchAction = "";
2380
+ } else if (this.supportsPointerEvents) {
2381
+ style.touchAction = "";
2382
+ }
2383
+ }
2384
+ if (this.supportsPointerEvents) {
2385
+ globalThis.document.removeEventListener("pointermove", this._onPointerMove, true);
2386
+ this.domElement.removeEventListener("pointerdown", this._onPointerDown, true);
2387
+ this.domElement.removeEventListener("pointerleave", this._onPointerOverOut, true);
2388
+ this.domElement.removeEventListener("pointerover", this._onPointerOverOut, true);
2389
+ globalThis.removeEventListener("pointerup", this._onPointerUp, true);
2390
+ } else {
2391
+ globalThis.document.removeEventListener("mousemove", this._onPointerMove, true);
2392
+ this.domElement.removeEventListener("mousedown", this._onPointerDown, true);
2393
+ this.domElement.removeEventListener("mouseout", this._onPointerOverOut, true);
2394
+ this.domElement.removeEventListener("mouseover", this._onPointerOverOut, true);
2395
+ globalThis.removeEventListener("mouseup", this._onPointerUp, true);
2396
+ if (this.supportsTouchEvents) {
2397
+ this.domElement.removeEventListener("touchstart", this._onPointerDown, true);
2398
+ this.domElement.removeEventListener("touchend", this._onPointerUp, true);
2399
+ this.domElement.removeEventListener("touchmove", this._onPointerMove, true);
2400
+ }
2401
+ }
2402
+ this.domElement.removeEventListener("wheel", this.onWheel, true);
2403
+ this.domElement = null;
2404
+ this._eventsAdded = false;
2405
+ }
2406
+ /**
2407
+ * Maps coordinates from DOM/screen space into PixiJS normalized coordinates.
2408
+ * This takes into account the current scale, position, and resolution of the DOM element.
2409
+ * @param point - The point to store the mapped coordinates in
2410
+ * @param x - The x coordinate in DOM/client space
2411
+ * @param y - The y coordinate in DOM/client space
2412
+ * @example
2413
+ * ```ts
2414
+ * // Map mouse coordinates to PixiJS space
2415
+ * const point = new Point();
2416
+ * app.renderer.events.mapPositionToPoint(
2417
+ * point,
2418
+ * event.clientX,
2419
+ * event.clientY
2420
+ * );
2421
+ * console.log('Mapped position:', point.x, point.y);
2422
+ *
2423
+ * // Using with pointer events
2424
+ * sprite.on('pointermove', (event) => {
2425
+ * // event.global already contains mapped coordinates
2426
+ * console.log('Global:', event.global.x, event.global.y);
2427
+ *
2428
+ * // Map to local coordinates
2429
+ * const local = event.getLocalPosition(sprite);
2430
+ * console.log('Local:', local.x, local.y);
2431
+ * });
2432
+ * ```
2433
+ * @remarks
2434
+ * - Accounts for element scaling and positioning
2435
+ * - Adjusts for device pixel ratio/resolution
2436
+ */
2437
+ mapPositionToPoint(point, x, y) {
2438
+ const rect = this.domElement.isConnected ? this.domElement.getBoundingClientRect() : {
2439
+ width: this.domElement.width,
2440
+ height: this.domElement.height,
2441
+ left: 0,
2442
+ top: 0
2443
+ };
2444
+ const resolutionMultiplier = 1 / this.resolution;
2445
+ point.x = (x - rect.left) * (this.domElement.width / rect.width) * resolutionMultiplier;
2446
+ point.y = (y - rect.top) * (this.domElement.height / rect.height) * resolutionMultiplier;
2447
+ }
2448
+ /**
2449
+ * Ensures that the original event object contains all data that a regular pointer event would have
2450
+ * @param event - The original event data from a touch or mouse event
2451
+ * @returns An array containing a single normalized pointer event, in the case of a pointer
2452
+ * or mouse event, or a multiple normalized pointer events if there are multiple changed touches
2453
+ */
2454
+ _normalizeToPointerData(event) {
2455
+ const normalizedEvents = [];
2456
+ if (this.supportsTouchEvents && event instanceof TouchEvent) {
2457
+ for (let i = 0, li = event.changedTouches.length; i < li; i++) {
2458
+ const touch = event.changedTouches[i];
2459
+ if (typeof touch.button === "undefined") touch.button = 0;
2460
+ if (typeof touch.buttons === "undefined") touch.buttons = 1;
2461
+ if (typeof touch.isPrimary === "undefined") {
2462
+ touch.isPrimary = event.touches.length === 1 && event.type === "touchstart";
2463
+ }
2464
+ if (typeof touch.width === "undefined") touch.width = touch.radiusX || 1;
2465
+ if (typeof touch.height === "undefined") touch.height = touch.radiusY || 1;
2466
+ if (typeof touch.tiltX === "undefined") touch.tiltX = 0;
2467
+ if (typeof touch.tiltY === "undefined") touch.tiltY = 0;
2468
+ if (typeof touch.pointerType === "undefined") touch.pointerType = "touch";
2469
+ if (typeof touch.pointerId === "undefined") touch.pointerId = touch.identifier || 0;
2470
+ if (typeof touch.pressure === "undefined") touch.pressure = touch.force || 0.5;
2471
+ if (typeof touch.twist === "undefined") touch.twist = 0;
2472
+ if (typeof touch.tangentialPressure === "undefined") touch.tangentialPressure = 0;
2473
+ if (typeof touch.layerX === "undefined") touch.layerX = touch.offsetX = touch.clientX;
2474
+ if (typeof touch.layerY === "undefined") touch.layerY = touch.offsetY = touch.clientY;
2475
+ touch.isNormalized = true;
2476
+ touch.type = event.type;
2477
+ normalizedEvents.push(touch);
2478
+ }
2479
+ } else if (!globalThis.MouseEvent || event instanceof MouseEvent && (!this.supportsPointerEvents || !(event instanceof globalThis.PointerEvent))) {
2480
+ const tempEvent = event;
2481
+ if (typeof tempEvent.isPrimary === "undefined") tempEvent.isPrimary = true;
2482
+ if (typeof tempEvent.width === "undefined") tempEvent.width = 1;
2483
+ if (typeof tempEvent.height === "undefined") tempEvent.height = 1;
2484
+ if (typeof tempEvent.tiltX === "undefined") tempEvent.tiltX = 0;
2485
+ if (typeof tempEvent.tiltY === "undefined") tempEvent.tiltY = 0;
2486
+ if (typeof tempEvent.pointerType === "undefined") tempEvent.pointerType = "mouse";
2487
+ if (typeof tempEvent.pointerId === "undefined") tempEvent.pointerId = MOUSE_POINTER_ID;
2488
+ if (typeof tempEvent.pressure === "undefined") tempEvent.pressure = 0.5;
2489
+ if (typeof tempEvent.twist === "undefined") tempEvent.twist = 0;
2490
+ if (typeof tempEvent.tangentialPressure === "undefined") tempEvent.tangentialPressure = 0;
2491
+ tempEvent.isNormalized = true;
2492
+ normalizedEvents.push(tempEvent);
2493
+ } else {
2494
+ normalizedEvents.push(event);
2495
+ }
2496
+ return normalizedEvents;
2497
+ }
2498
+ /**
2499
+ * Normalizes the native {@link https://w3c.github.io/uievents/#interface-wheelevent WheelEvent}.
2500
+ *
2501
+ * The returned {@link FederatedWheelEvent} is a shared instance. It will not persist across
2502
+ * multiple native wheel events.
2503
+ * @param nativeEvent - The native wheel event that occurred on the canvas.
2504
+ * @returns A federated wheel event.
2505
+ */
2506
+ normalizeWheelEvent(nativeEvent) {
2507
+ const event = this._rootWheelEvent;
2508
+ this._transferMouseData(event, nativeEvent);
2509
+ event.deltaX = nativeEvent.deltaX;
2510
+ event.deltaY = nativeEvent.deltaY;
2511
+ event.deltaZ = nativeEvent.deltaZ;
2512
+ event.deltaMode = nativeEvent.deltaMode;
2513
+ this.mapPositionToPoint(event.screen, nativeEvent.clientX, nativeEvent.clientY);
2514
+ event.global.copyFrom(event.screen);
2515
+ event.offset.copyFrom(event.screen);
2516
+ event.nativeEvent = nativeEvent;
2517
+ event.type = nativeEvent.type;
2518
+ return event;
2519
+ }
2520
+ /**
2521
+ * Normalizes the `nativeEvent` into a federateed {@link FederatedPointerEvent}.
2522
+ * @param event
2523
+ * @param nativeEvent
2524
+ */
2525
+ _bootstrapEvent(event, nativeEvent) {
2526
+ event.originalEvent = null;
2527
+ event.nativeEvent = nativeEvent;
2528
+ event.pointerId = nativeEvent.pointerId;
2529
+ event.width = nativeEvent.width;
2530
+ event.height = nativeEvent.height;
2531
+ event.isPrimary = nativeEvent.isPrimary;
2532
+ event.pointerType = nativeEvent.pointerType;
2533
+ event.pressure = nativeEvent.pressure;
2534
+ event.tangentialPressure = nativeEvent.tangentialPressure;
2535
+ event.tiltX = nativeEvent.tiltX;
2536
+ event.tiltY = nativeEvent.tiltY;
2537
+ event.twist = nativeEvent.twist;
2538
+ this._transferMouseData(event, nativeEvent);
2539
+ this.mapPositionToPoint(event.screen, nativeEvent.clientX, nativeEvent.clientY);
2540
+ event.global.copyFrom(event.screen);
2541
+ event.offset.copyFrom(event.screen);
2542
+ event.isTrusted = nativeEvent.isTrusted;
2543
+ if (event.type === "pointerleave") {
2544
+ event.type = "pointerout";
2545
+ }
2546
+ if (event.type.startsWith("mouse")) {
2547
+ event.type = event.type.replace("mouse", "pointer");
2548
+ }
2549
+ if (event.type.startsWith("touch")) {
2550
+ event.type = TOUCH_TO_POINTER[event.type] || event.type;
2551
+ }
2552
+ return event;
2553
+ }
2554
+ /**
2555
+ * Transfers base & mouse event data from the `nativeEvent` to the federated event.
2556
+ * @param event
2557
+ * @param nativeEvent
2558
+ */
2559
+ _transferMouseData(event, nativeEvent) {
2560
+ event.isTrusted = nativeEvent.isTrusted;
2561
+ event.srcElement = nativeEvent.srcElement;
2562
+ event.timeStamp = performance.now();
2563
+ event.type = nativeEvent.type;
2564
+ event.altKey = nativeEvent.altKey;
2565
+ event.button = nativeEvent.button;
2566
+ event.buttons = nativeEvent.buttons;
2567
+ event.client.x = nativeEvent.clientX;
2568
+ event.client.y = nativeEvent.clientY;
2569
+ event.ctrlKey = nativeEvent.ctrlKey;
2570
+ event.metaKey = nativeEvent.metaKey;
2571
+ event.movement.x = nativeEvent.movementX;
2572
+ event.movement.y = nativeEvent.movementY;
2573
+ event.page.x = nativeEvent.pageX;
2574
+ event.page.y = nativeEvent.pageY;
2575
+ event.relatedTarget = null;
2576
+ event.shiftKey = nativeEvent.shiftKey;
2577
+ }
2578
+ };
2579
+ _EventSystem.extension = {
2580
+ name: "events",
2581
+ type: [
2582
+ ExtensionType.WebGLSystem,
2583
+ ExtensionType.CanvasSystem,
2584
+ ExtensionType.WebGPUSystem
2585
+ ],
2586
+ priority: -1
2587
+ };
2588
+ _EventSystem.defaultEventFeatures = {
2589
+ /** Enables pointer events associated with pointer movement. */
2590
+ move: true,
2591
+ /** Enables global pointer move events. */
2592
+ globalMove: true,
2593
+ /** Enables pointer events associated with clicking. */
2594
+ click: true,
2595
+ /** Enables wheel events. */
2596
+ wheel: true
2597
+ };
2598
+ let EventSystem = _EventSystem;
2599
+ const FederatedContainer = {
2600
+ onclick: null,
2601
+ onmousedown: null,
2602
+ onmouseenter: null,
2603
+ onmouseleave: null,
2604
+ onmousemove: null,
2605
+ onglobalmousemove: null,
2606
+ onmouseout: null,
2607
+ onmouseover: null,
2608
+ onmouseup: null,
2609
+ onmouseupoutside: null,
2610
+ onpointercancel: null,
2611
+ onpointerdown: null,
2612
+ onpointerenter: null,
2613
+ onpointerleave: null,
2614
+ onpointermove: null,
2615
+ onglobalpointermove: null,
2616
+ onpointerout: null,
2617
+ onpointerover: null,
2618
+ onpointertap: null,
2619
+ onpointerup: null,
2620
+ onpointerupoutside: null,
2621
+ onrightclick: null,
2622
+ onrightdown: null,
2623
+ onrightup: null,
2624
+ onrightupoutside: null,
2625
+ ontap: null,
2626
+ ontouchcancel: null,
2627
+ ontouchend: null,
2628
+ ontouchendoutside: null,
2629
+ ontouchmove: null,
2630
+ onglobaltouchmove: null,
2631
+ ontouchstart: null,
2632
+ onwheel: null,
2633
+ get interactive() {
2634
+ return this.eventMode === "dynamic" || this.eventMode === "static";
2635
+ },
2636
+ set interactive(value) {
2637
+ this.eventMode = value ? "static" : "passive";
2638
+ },
2639
+ _internalEventMode: void 0,
2640
+ get eventMode() {
2641
+ return this._internalEventMode ?? EventSystem.defaultEventMode;
2642
+ },
2643
+ set eventMode(value) {
2644
+ this._internalEventMode = value;
2645
+ },
2646
+ isInteractive() {
2647
+ return this.eventMode === "static" || this.eventMode === "dynamic";
2648
+ },
2649
+ interactiveChildren: true,
2650
+ hitArea: null,
2651
+ addEventListener(type, listener, options) {
2652
+ const capture = typeof options === "boolean" && options || typeof options === "object" && options.capture;
2653
+ const signal = typeof options === "object" ? options.signal : void 0;
2654
+ const once = typeof options === "object" ? options.once === true : false;
2655
+ const context = typeof listener === "function" ? void 0 : listener;
2656
+ type = capture ? `${type}capture` : type;
2657
+ const listenerFn = typeof listener === "function" ? listener : listener.handleEvent;
2658
+ const emitter = this;
2659
+ if (signal) {
2660
+ signal.addEventListener("abort", () => {
2661
+ emitter.off(type, listenerFn, context);
2662
+ });
2663
+ }
2664
+ if (once) {
2665
+ emitter.once(type, listenerFn, context);
2666
+ } else {
2667
+ emitter.on(type, listenerFn, context);
2668
+ }
2669
+ },
2670
+ removeEventListener(type, listener, options) {
2671
+ const capture = typeof options === "boolean" && options || typeof options === "object" && options.capture;
2672
+ const context = typeof listener === "function" ? void 0 : listener;
2673
+ type = capture ? `${type}capture` : type;
2674
+ listener = typeof listener === "function" ? listener : listener.handleEvent;
2675
+ this.off(type, listener, context);
2676
+ },
2677
+ dispatchEvent(e) {
2678
+ if (!(e instanceof FederatedEvent)) {
2679
+ throw new Error("Container cannot propagate events outside of the Federated Events API");
2680
+ }
2681
+ e.defaultPrevented = false;
2682
+ e.path = null;
2683
+ e.target = this;
2684
+ e.manager.dispatchEvent(e);
2685
+ return !e.defaultPrevented;
2686
+ }
2687
+ };
2688
+ extensions.add(AccessibilitySystem);
2689
+ extensions.mixin(Container, accessibilityTarget);
2690
+ extensions.add(EventSystem);
2691
+ extensions.mixin(Container, FederatedContainer);