@ohos-ports/pixi-accessibility 7.4.3-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2013-2023 Mathew Groves, Chad Engler
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,13 @@
1
+ # @pixi/accessibility
2
+
3
+ ## Installation
4
+
5
+ ```bash
6
+ npm install @pixi/accessibility
7
+ ```
8
+
9
+ ## Usage
10
+
11
+ ```js
12
+ import '@pixi/accessibility';
13
+ ```
package/global.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ declare namespace GlobalMixins
2
+ {
3
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
4
+ interface DisplayObject extends Partial<import('@pixi/accessibility').IAccessibleTarget>
5
+ {
6
+
7
+ }
8
+ }
@@ -0,0 +1,147 @@
1
+ import type { ExtensionMetadata, IRenderer, Rectangle } from '@pixi/core';
2
+ import type { IAccessibleHTMLElement } from './accessibleTarget';
3
+ /**
4
+ * The Accessibility manager recreates the ability to tab and have content read by screen readers.
5
+ * This is very important as it can possibly help people with disabilities access PixiJS content.
6
+ *
7
+ * A DisplayObject can be made accessible just like it can be made interactive. This manager will map the
8
+ * events as if the mouse was being used, minimizing the effort required to implement.
9
+ *
10
+ * An instance of this class is automatically created by default, and can be found at `renderer.plugins.accessibility`
11
+ * @class
12
+ * @memberof PIXI
13
+ */
14
+ export declare class AccessibilityManager {
15
+ /** @ignore */
16
+ static extension: ExtensionMetadata;
17
+ /** Setting this to true will visually show the divs. */
18
+ debug: boolean;
19
+ /**
20
+ * The renderer this accessibility manager works for.
21
+ * @type {PIXI.CanvasRenderer|PIXI.Renderer}
22
+ */
23
+ renderer: IRenderer;
24
+ /** Internal variable, see isActive getter. */
25
+ private _isActive;
26
+ /** Internal variable, see isMobileAccessibility getter. */
27
+ private _isMobileAccessibility;
28
+ /** Button element for handling touch hooks. */
29
+ private _hookDiv;
30
+ /** This is the dom element that will sit over the PixiJS element. This is where the div overlays will go. */
31
+ private div;
32
+ /** A simple pool for storing divs. */
33
+ private pool;
34
+ /** This is a tick used to check if an object is no longer being rendered. */
35
+ private renderId;
36
+ /** The array of currently active accessible items. */
37
+ private children;
38
+ /** Count to throttle div updates on android devices. */
39
+ private androidUpdateCount;
40
+ /** The frequency to update the div elements. */
41
+ private androidUpdateFrequency;
42
+ /**
43
+ * @param {PIXI.CanvasRenderer|PIXI.Renderer} renderer - A reference to the current renderer
44
+ */
45
+ constructor(renderer: IRenderer);
46
+ /**
47
+ * Value of `true` if accessibility is currently active and accessibility layers are showing.
48
+ * @member {boolean}
49
+ * @readonly
50
+ */
51
+ get isActive(): boolean;
52
+ /**
53
+ * Value of `true` if accessibility is enabled for touch devices.
54
+ * @member {boolean}
55
+ * @readonly
56
+ */
57
+ get isMobileAccessibility(): boolean;
58
+ /**
59
+ * Creates the touch hooks.
60
+ * @private
61
+ */
62
+ private createTouchHook;
63
+ /**
64
+ * Destroys the touch hooks.
65
+ * @private
66
+ */
67
+ private destroyTouchHook;
68
+ /**
69
+ * Activating will cause the Accessibility layer to be shown.
70
+ * This is called when a user presses the tab key.
71
+ * @private
72
+ */
73
+ private activate;
74
+ /**
75
+ * Deactivating will cause the Accessibility layer to be hidden.
76
+ * This is called when a user moves the mouse.
77
+ * @private
78
+ */
79
+ private deactivate;
80
+ /**
81
+ * This recursive function will run through the scene graph and add any new accessible objects to the DOM layer.
82
+ * @private
83
+ * @param {PIXI.Container} displayObject - The DisplayObject to check.
84
+ */
85
+ private updateAccessibleObjects;
86
+ /**
87
+ * Before each render this function will ensure that all divs are mapped correctly to their DisplayObjects.
88
+ * @private
89
+ */
90
+ private update;
91
+ /**
92
+ * private function that will visually add the information to the
93
+ * accessability div
94
+ * @param {HTMLElement} div -
95
+ */
96
+ updateDebugHTML(div: IAccessibleHTMLElement): void;
97
+ /**
98
+ * Adjust the hit area based on the bounds of a display object
99
+ * @param {PIXI.Rectangle} hitArea - Bounds of the child
100
+ */
101
+ capHitArea(hitArea: Rectangle): void;
102
+ /**
103
+ * Adds a DisplayObject to the accessibility manager
104
+ * @private
105
+ * @param {PIXI.DisplayObject} displayObject - The child to make accessible.
106
+ */
107
+ private addChild;
108
+ /**
109
+ * Dispatch events with the EventSystem.
110
+ * @param e
111
+ * @param type
112
+ * @private
113
+ */
114
+ private _dispatchEvent;
115
+ /**
116
+ * Maps the div button press to pixi's EventSystem (click)
117
+ * @private
118
+ * @param {MouseEvent} e - The click event.
119
+ */
120
+ private _onClick;
121
+ /**
122
+ * Maps the div focus events to pixi's EventSystem (mouseover)
123
+ * @private
124
+ * @param {FocusEvent} e - The focus event.
125
+ */
126
+ private _onFocus;
127
+ /**
128
+ * Maps the div focus events to pixi's EventSystem (mouseout)
129
+ * @private
130
+ * @param {FocusEvent} e - The focusout event.
131
+ */
132
+ private _onFocusOut;
133
+ /**
134
+ * Is called when a key is pressed
135
+ * @private
136
+ * @param {KeyboardEvent} e - The keydown event.
137
+ */
138
+ private _onKeyDown;
139
+ /**
140
+ * Is called when the mouse moves across the renderer element
141
+ * @private
142
+ * @param {MouseEvent} e - The mouse event.
143
+ */
144
+ private _onMouseMove;
145
+ /** Destroys the accessibility manager */
146
+ destroy(): void;
147
+ }
@@ -0,0 +1,193 @@
1
+ "use strict";
2
+ var core = require("@pixi/core"), display = require("@pixi/display"), events = require("@pixi/events"), accessibleTarget = require("./accessibleTarget.js");
3
+ display.DisplayObject.mixin(accessibleTarget.accessibleTarget);
4
+ const KEY_CODE_TAB = 9, DIV_TOUCH_SIZE = 100, DIV_TOUCH_POS_X = 0, DIV_TOUCH_POS_Y = 0, DIV_TOUCH_ZINDEX = 2, DIV_HOOK_SIZE = 1, DIV_HOOK_POS_X = -1e3, DIV_HOOK_POS_Y = -1e3, DIV_HOOK_ZINDEX = 2;
5
+ class AccessibilityManager {
6
+ // 2fps
7
+ /**
8
+ * @param {PIXI.CanvasRenderer|PIXI.Renderer} renderer - A reference to the current renderer
9
+ */
10
+ constructor(renderer) {
11
+ this.debug = !1, this._isActive = !1, this._isMobileAccessibility = !1, this.pool = [], this.renderId = 0, this.children = [], this.androidUpdateCount = 0, this.androidUpdateFrequency = 500, this._hookDiv = null, (core.utils.isMobile.tablet || core.utils.isMobile.phone) && this.createTouchHook();
12
+ const div = document.createElement("div");
13
+ div.style.width = `${DIV_TOUCH_SIZE}px`, div.style.height = `${DIV_TOUCH_SIZE}px`, div.style.position = "absolute", div.style.top = `${DIV_TOUCH_POS_X}px`, div.style.left = `${DIV_TOUCH_POS_Y}px`, div.style.zIndex = DIV_TOUCH_ZINDEX.toString(), this.div = div, this.renderer = renderer, this._onKeyDown = this._onKeyDown.bind(this), this._onMouseMove = this._onMouseMove.bind(this), globalThis.addEventListener("keydown", this._onKeyDown, !1);
14
+ }
15
+ /**
16
+ * Value of `true` if accessibility is currently active and accessibility layers are showing.
17
+ * @member {boolean}
18
+ * @readonly
19
+ */
20
+ get isActive() {
21
+ return this._isActive;
22
+ }
23
+ /**
24
+ * Value of `true` if accessibility is enabled for touch devices.
25
+ * @member {boolean}
26
+ * @readonly
27
+ */
28
+ get isMobileAccessibility() {
29
+ return this._isMobileAccessibility;
30
+ }
31
+ /**
32
+ * Creates the touch hooks.
33
+ * @private
34
+ */
35
+ createTouchHook() {
36
+ const hookDiv = document.createElement("button");
37
+ hookDiv.style.width = `${DIV_HOOK_SIZE}px`, hookDiv.style.height = `${DIV_HOOK_SIZE}px`, hookDiv.style.position = "absolute", hookDiv.style.top = `${DIV_HOOK_POS_X}px`, hookDiv.style.left = `${DIV_HOOK_POS_Y}px`, hookDiv.style.zIndex = DIV_HOOK_ZINDEX.toString(), hookDiv.style.backgroundColor = "#FF0000", hookDiv.title = "select to enable accessibility for this content", hookDiv.addEventListener("focus", () => {
38
+ this._isMobileAccessibility = !0, this.activate(), this.destroyTouchHook();
39
+ }), document.body.appendChild(hookDiv), this._hookDiv = hookDiv;
40
+ }
41
+ /**
42
+ * Destroys the touch hooks.
43
+ * @private
44
+ */
45
+ destroyTouchHook() {
46
+ this._hookDiv && (document.body.removeChild(this._hookDiv), this._hookDiv = null);
47
+ }
48
+ /**
49
+ * Activating will cause the Accessibility layer to be shown.
50
+ * This is called when a user presses the tab key.
51
+ * @private
52
+ */
53
+ activate() {
54
+ this._isActive || (this._isActive = !0, globalThis.document.addEventListener("mousemove", this._onMouseMove, !0), globalThis.removeEventListener("keydown", this._onKeyDown, !1), this.renderer.on("postrender", this.update, this), (this.renderer.view.parentNode || document.body)?.appendChild(this.div));
55
+ }
56
+ /**
57
+ * Deactivating will cause the Accessibility layer to be hidden.
58
+ * This is called when a user moves the mouse.
59
+ * @private
60
+ */
61
+ deactivate() {
62
+ !this._isActive || this._isMobileAccessibility || (this._isActive = !1, globalThis.document.removeEventListener("mousemove", this._onMouseMove, !0), globalThis.addEventListener("keydown", this._onKeyDown, !1), this.renderer.off("postrender", this.update), this.div.parentNode?.removeChild(this.div));
63
+ }
64
+ /**
65
+ * This recursive function will run through the scene graph and add any new accessible objects to the DOM layer.
66
+ * @private
67
+ * @param {PIXI.Container} displayObject - The DisplayObject to check.
68
+ */
69
+ updateAccessibleObjects(displayObject) {
70
+ if (!displayObject.visible || !displayObject.accessibleChildren)
71
+ return;
72
+ displayObject.accessible && displayObject.isInteractive() && (displayObject._accessibleActive || this.addChild(displayObject), displayObject.renderId = this.renderId);
73
+ const children = displayObject.children;
74
+ if (children)
75
+ for (let i = 0; i < children.length; i++)
76
+ this.updateAccessibleObjects(children[i]);
77
+ }
78
+ /**
79
+ * Before each render this function will ensure that all divs are mapped correctly to their DisplayObjects.
80
+ * @private
81
+ */
82
+ update() {
83
+ const now = performance.now();
84
+ if (core.utils.isMobile.android.device && now < this.androidUpdateCount || (this.androidUpdateCount = now + this.androidUpdateFrequency, !this.renderer.renderingToScreen))
85
+ return;
86
+ this.renderer.lastObjectRendered && this.updateAccessibleObjects(this.renderer.lastObjectRendered);
87
+ const { x, y, width, height } = this.renderer.view.getBoundingClientRect(), { width: viewWidth, height: viewHeight, resolution } = this.renderer, sx = width / viewWidth * resolution, sy = height / viewHeight * resolution;
88
+ let div = this.div;
89
+ div.style.left = `${x}px`, div.style.top = `${y}px`, div.style.width = `${viewWidth}px`, div.style.height = `${viewHeight}px`;
90
+ for (let i = 0; i < this.children.length; i++) {
91
+ const child = this.children[i];
92
+ if (child.renderId !== this.renderId)
93
+ child._accessibleActive = !1, core.utils.removeItems(this.children, i, 1), this.div.removeChild(child._accessibleDiv), this.pool.push(child._accessibleDiv), child._accessibleDiv = null, i--;
94
+ else {
95
+ div = child._accessibleDiv;
96
+ let hitArea = child.hitArea;
97
+ const wt = child.worldTransform;
98
+ child.hitArea ? (div.style.left = `${(wt.tx + hitArea.x * wt.a) * sx}px`, div.style.top = `${(wt.ty + hitArea.y * wt.d) * sy}px`, div.style.width = `${hitArea.width * wt.a * sx}px`, div.style.height = `${hitArea.height * wt.d * sy}px`) : (hitArea = child.getBounds(), this.capHitArea(hitArea), div.style.left = `${hitArea.x * sx}px`, div.style.top = `${hitArea.y * sy}px`, div.style.width = `${hitArea.width * sx}px`, div.style.height = `${hitArea.height * sy}px`, div.title !== child.accessibleTitle && child.accessibleTitle !== null && (div.title = child.accessibleTitle), div.getAttribute("aria-label") !== child.accessibleHint && child.accessibleHint !== null && div.setAttribute("aria-label", child.accessibleHint)), (child.accessibleTitle !== div.title || child.tabIndex !== div.tabIndex) && (div.title = child.accessibleTitle, div.tabIndex = child.tabIndex, this.debug && this.updateDebugHTML(div));
99
+ }
100
+ }
101
+ this.renderId++;
102
+ }
103
+ /**
104
+ * private function that will visually add the information to the
105
+ * accessability div
106
+ * @param {HTMLElement} div -
107
+ */
108
+ updateDebugHTML(div) {
109
+ div.innerHTML = `type: ${div.type}</br> title : ${div.title}</br> tabIndex: ${div.tabIndex}`;
110
+ }
111
+ /**
112
+ * Adjust the hit area based on the bounds of a display object
113
+ * @param {PIXI.Rectangle} hitArea - Bounds of the child
114
+ */
115
+ capHitArea(hitArea) {
116
+ hitArea.x < 0 && (hitArea.width += hitArea.x, hitArea.x = 0), hitArea.y < 0 && (hitArea.height += hitArea.y, hitArea.y = 0);
117
+ const { width: viewWidth, height: viewHeight } = this.renderer;
118
+ hitArea.x + hitArea.width > viewWidth && (hitArea.width = viewWidth - hitArea.x), hitArea.y + hitArea.height > viewHeight && (hitArea.height = viewHeight - hitArea.y);
119
+ }
120
+ /**
121
+ * Adds a DisplayObject to the accessibility manager
122
+ * @private
123
+ * @param {PIXI.DisplayObject} displayObject - The child to make accessible.
124
+ */
125
+ addChild(displayObject) {
126
+ let div = this.pool.pop();
127
+ div || (div = document.createElement("button"), div.style.width = `${DIV_TOUCH_SIZE}px`, div.style.height = `${DIV_TOUCH_SIZE}px`, div.style.backgroundColor = this.debug ? "rgba(255,255,255,0.5)" : "transparent", div.style.position = "absolute", div.style.zIndex = DIV_TOUCH_ZINDEX.toString(), div.style.borderStyle = "none", navigator.userAgent.toLowerCase().includes("chrome") ? div.setAttribute("aria-live", "off") : div.setAttribute("aria-live", "polite"), navigator.userAgent.match(/rv:.*Gecko\//) ? div.setAttribute("aria-relevant", "additions") : div.setAttribute("aria-relevant", "text"), div.addEventListener("click", this._onClick.bind(this)), div.addEventListener("focus", this._onFocus.bind(this)), div.addEventListener("focusout", this._onFocusOut.bind(this))), div.style.pointerEvents = displayObject.accessiblePointerEvents, div.type = displayObject.accessibleType, displayObject.accessibleTitle && displayObject.accessibleTitle !== null ? div.title = displayObject.accessibleTitle : (!displayObject.accessibleHint || displayObject.accessibleHint === null) && (div.title = `displayObject ${displayObject.tabIndex}`), displayObject.accessibleHint && displayObject.accessibleHint !== null && div.setAttribute("aria-label", displayObject.accessibleHint), this.debug && this.updateDebugHTML(div), displayObject._accessibleActive = !0, displayObject._accessibleDiv = div, div.displayObject = displayObject, this.children.push(displayObject), this.div.appendChild(displayObject._accessibleDiv), displayObject._accessibleDiv.tabIndex = displayObject.tabIndex;
128
+ }
129
+ /**
130
+ * Dispatch events with the EventSystem.
131
+ * @param e
132
+ * @param type
133
+ * @private
134
+ */
135
+ _dispatchEvent(e, type) {
136
+ const { displayObject: target } = e.target, boundry = this.renderer.events.rootBoundary, event = Object.assign(new events.FederatedEvent(boundry), { target });
137
+ boundry.rootTarget = this.renderer.lastObjectRendered, type.forEach((type2) => boundry.dispatchEvent(event, type2));
138
+ }
139
+ /**
140
+ * Maps the div button press to pixi's EventSystem (click)
141
+ * @private
142
+ * @param {MouseEvent} e - The click event.
143
+ */
144
+ _onClick(e) {
145
+ this._dispatchEvent(e, ["click", "pointertap", "tap"]);
146
+ }
147
+ /**
148
+ * Maps the div focus events to pixi's EventSystem (mouseover)
149
+ * @private
150
+ * @param {FocusEvent} e - The focus event.
151
+ */
152
+ _onFocus(e) {
153
+ e.target.getAttribute("aria-live") || e.target.setAttribute("aria-live", "assertive"), this._dispatchEvent(e, ["mouseover"]);
154
+ }
155
+ /**
156
+ * Maps the div focus events to pixi's EventSystem (mouseout)
157
+ * @private
158
+ * @param {FocusEvent} e - The focusout event.
159
+ */
160
+ _onFocusOut(e) {
161
+ e.target.getAttribute("aria-live") || e.target.setAttribute("aria-live", "polite"), this._dispatchEvent(e, ["mouseout"]);
162
+ }
163
+ /**
164
+ * Is called when a key is pressed
165
+ * @private
166
+ * @param {KeyboardEvent} e - The keydown event.
167
+ */
168
+ _onKeyDown(e) {
169
+ e.keyCode === KEY_CODE_TAB && this.activate();
170
+ }
171
+ /**
172
+ * Is called when the mouse moves across the renderer element
173
+ * @private
174
+ * @param {MouseEvent} e - The mouse event.
175
+ */
176
+ _onMouseMove(e) {
177
+ e.movementX === 0 && e.movementY === 0 || this.deactivate();
178
+ }
179
+ /** Destroys the accessibility manager */
180
+ destroy() {
181
+ this.destroyTouchHook(), this.div = null, globalThis.document.removeEventListener("mousemove", this._onMouseMove, !0), globalThis.removeEventListener("keydown", this._onKeyDown), this.pool = null, this.children = null, this.renderer = null;
182
+ }
183
+ }
184
+ AccessibilityManager.extension = {
185
+ name: "accessibility",
186
+ type: [
187
+ core.ExtensionType.RendererPlugin,
188
+ core.ExtensionType.CanvasRendererPlugin
189
+ ]
190
+ };
191
+ core.extensions.add(AccessibilityManager);
192
+ exports.AccessibilityManager = AccessibilityManager;
193
+ //# sourceMappingURL=AccessibilityManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccessibilityManager.js","sources":["../src/AccessibilityManager.ts"],"sourcesContent":["import { extensions, ExtensionType, utils } from '@pixi/core';\nimport { DisplayObject } from '@pixi/display';\nimport { FederatedEvent } from '@pixi/events';\nimport { accessibleTarget } from './accessibleTarget';\n\nimport type { ExtensionMetadata, IRenderer, Rectangle } from '@pixi/core';\nimport type { Container } from '@pixi/display';\nimport type { IAccessibleHTMLElement } from './accessibleTarget';\n\n// add some extra variables to the container..\nDisplayObject.mixin(accessibleTarget);\n\nconst KEY_CODE_TAB = 9;\n\nconst DIV_TOUCH_SIZE = 100;\nconst DIV_TOUCH_POS_X = 0;\nconst DIV_TOUCH_POS_Y = 0;\nconst DIV_TOUCH_ZINDEX = 2;\n\nconst DIV_HOOK_SIZE = 1;\nconst DIV_HOOK_POS_X = -1000;\nconst DIV_HOOK_POS_Y = -1000;\nconst DIV_HOOK_ZINDEX = 2;\n\n/**\n * The Accessibility manager recreates the ability to tab and have content read by screen readers.\n * This is very important as it can possibly help people with disabilities access PixiJS content.\n *\n * A DisplayObject can be made accessible just like it can be made interactive. This manager will map the\n * events as if the mouse was being used, minimizing the effort required to implement.\n *\n * An instance of this class is automatically created by default, and can be found at `renderer.plugins.accessibility`\n * @class\n * @memberof PIXI\n */\nexport class AccessibilityManager\n{\n /** @ignore */\n static extension: ExtensionMetadata = {\n name: 'accessibility',\n type: [\n ExtensionType.RendererPlugin,\n ExtensionType.CanvasRendererPlugin,\n ],\n };\n\n /** Setting this to true will visually show the divs. */\n public debug = false;\n\n /**\n * The renderer this accessibility manager works for.\n * @type {PIXI.CanvasRenderer|PIXI.Renderer}\n */\n public renderer: IRenderer;\n\n /** Internal variable, see isActive getter. */\n private _isActive = false;\n\n /** Internal variable, see isMobileAccessibility getter. */\n private _isMobileAccessibility = false;\n\n /** Button element for handling touch hooks. */\n private _hookDiv: HTMLElement;\n\n /** This is the dom element that will sit over the PixiJS element. This is where the div overlays will go. */\n private div: HTMLElement;\n\n /** A simple pool for storing divs. */\n private pool: IAccessibleHTMLElement[] = [];\n\n /** This is a tick used to check if an object is no longer being rendered. */\n private renderId = 0;\n\n /** The array of currently active accessible items. */\n private children: DisplayObject[] = [];\n\n /** Count to throttle div updates on android devices. */\n private androidUpdateCount = 0;\n\n /** The frequency to update the div elements. */\n private androidUpdateFrequency = 500; // 2fps\n\n /**\n * @param {PIXI.CanvasRenderer|PIXI.Renderer} renderer - A reference to the current renderer\n */\n constructor(renderer: IRenderer)\n {\n this._hookDiv = null;\n\n if (utils.isMobile.tablet || utils.isMobile.phone)\n {\n this.createTouchHook();\n }\n\n // first we create a div that will sit over the PixiJS element. This is where the div overlays will go.\n const div = document.createElement('div');\n\n div.style.width = `${DIV_TOUCH_SIZE}px`;\n div.style.height = `${DIV_TOUCH_SIZE}px`;\n div.style.position = 'absolute';\n div.style.top = `${DIV_TOUCH_POS_X}px`;\n div.style.left = `${DIV_TOUCH_POS_Y}px`;\n div.style.zIndex = DIV_TOUCH_ZINDEX.toString();\n\n this.div = div;\n this.renderer = renderer;\n\n /**\n * pre-bind the functions\n * @type {Function}\n * @private\n */\n this._onKeyDown = this._onKeyDown.bind(this);\n\n /**\n * pre-bind the functions\n * @type {Function}\n * @private\n */\n this._onMouseMove = this._onMouseMove.bind(this);\n\n // let listen for tab.. once pressed we can fire up and show the accessibility layer\n globalThis.addEventListener('keydown', this._onKeyDown, false);\n }\n\n /**\n * Value of `true` if accessibility is currently active and accessibility layers are showing.\n * @member {boolean}\n * @readonly\n */\n get isActive(): boolean\n {\n return this._isActive;\n }\n\n /**\n * Value of `true` if accessibility is enabled for touch devices.\n * @member {boolean}\n * @readonly\n */\n get isMobileAccessibility(): boolean\n {\n return this._isMobileAccessibility;\n }\n\n /**\n * Creates the touch hooks.\n * @private\n */\n private createTouchHook(): void\n {\n const hookDiv = document.createElement('button');\n\n hookDiv.style.width = `${DIV_HOOK_SIZE}px`;\n hookDiv.style.height = `${DIV_HOOK_SIZE}px`;\n hookDiv.style.position = 'absolute';\n hookDiv.style.top = `${DIV_HOOK_POS_X}px`;\n hookDiv.style.left = `${DIV_HOOK_POS_Y}px`;\n hookDiv.style.zIndex = DIV_HOOK_ZINDEX.toString();\n hookDiv.style.backgroundColor = '#FF0000';\n hookDiv.title = 'select to enable accessibility for this content';\n\n hookDiv.addEventListener('focus', () =>\n {\n this._isMobileAccessibility = true;\n this.activate();\n this.destroyTouchHook();\n });\n\n document.body.appendChild(hookDiv);\n this._hookDiv = hookDiv;\n }\n\n /**\n * Destroys the touch hooks.\n * @private\n */\n private destroyTouchHook(): void\n {\n if (!this._hookDiv)\n {\n return;\n }\n document.body.removeChild(this._hookDiv);\n this._hookDiv = null;\n }\n\n /**\n * Activating will cause the Accessibility layer to be shown.\n * This is called when a user presses the tab key.\n * @private\n */\n private activate(): void\n {\n if (this._isActive)\n {\n return;\n }\n\n this._isActive = true;\n\n globalThis.document.addEventListener('mousemove', this._onMouseMove, true);\n globalThis.removeEventListener('keydown', this._onKeyDown, false);\n\n this.renderer.on('postrender', this.update, this);\n this.renderer.view.parentNode?.appendChild(this.div);\n }\n\n /**\n * Deactivating will cause the Accessibility layer to be hidden.\n * This is called when a user moves the mouse.\n * @private\n */\n private deactivate(): void\n {\n if (!this._isActive || this._isMobileAccessibility)\n {\n return;\n }\n\n this._isActive = false;\n\n globalThis.document.removeEventListener('mousemove', this._onMouseMove, true);\n globalThis.addEventListener('keydown', this._onKeyDown, false);\n\n this.renderer.off('postrender', this.update);\n this.div.parentNode?.removeChild(this.div);\n }\n\n /**\n * This recursive function will run through the scene graph and add any new accessible objects to the DOM layer.\n * @private\n * @param {PIXI.Container} displayObject - The DisplayObject to check.\n */\n private updateAccessibleObjects(displayObject: Container): void\n {\n if (!displayObject.visible || !displayObject.accessibleChildren)\n {\n return;\n }\n\n if (displayObject.accessible && displayObject.isInteractive())\n {\n if (!displayObject._accessibleActive)\n {\n this.addChild(displayObject);\n }\n\n displayObject.renderId = this.renderId;\n }\n\n const children = displayObject.children;\n\n if (children)\n {\n for (let i = 0; i < children.length; i++)\n {\n this.updateAccessibleObjects(children[i] as Container);\n }\n }\n }\n\n /**\n * Before each render this function will ensure that all divs are mapped correctly to their DisplayObjects.\n * @private\n */\n private update(): void\n {\n /* On Android default web browser, tab order seems to be calculated by position rather than tabIndex,\n * moving buttons can cause focus to flicker between two buttons making it hard/impossible to navigate,\n * so I am just running update every half a second, seems to fix it.\n */\n const now = performance.now();\n\n if (utils.isMobile.android.device && now < this.androidUpdateCount)\n {\n return;\n }\n\n this.androidUpdateCount = now + this.androidUpdateFrequency;\n\n if (!this.renderer.renderingToScreen)\n {\n return;\n }\n\n // update children...\n if (this.renderer.lastObjectRendered)\n {\n this.updateAccessibleObjects(this.renderer.lastObjectRendered as Container);\n }\n\n const { x, y, width, height } = this.renderer.view.getBoundingClientRect();\n const { width: viewWidth, height: viewHeight, resolution } = this.renderer;\n\n const sx = (width / viewWidth) * resolution;\n const sy = (height / viewHeight) * resolution;\n\n let div = this.div;\n\n div.style.left = `${x}px`;\n div.style.top = `${y}px`;\n div.style.width = `${viewWidth}px`;\n div.style.height = `${viewHeight}px`;\n\n for (let i = 0; i < this.children.length; i++)\n {\n const child = this.children[i];\n\n if (child.renderId !== this.renderId)\n {\n child._accessibleActive = false;\n\n utils.removeItems(this.children, i, 1);\n this.div.removeChild(child._accessibleDiv);\n this.pool.push(child._accessibleDiv);\n child._accessibleDiv = null;\n\n i--;\n }\n else\n {\n // map div to display..\n div = child._accessibleDiv;\n let hitArea = child.hitArea as Rectangle;\n const wt = child.worldTransform;\n\n if (child.hitArea)\n {\n div.style.left = `${(wt.tx + (hitArea.x * wt.a)) * sx}px`;\n div.style.top = `${(wt.ty + (hitArea.y * wt.d)) * sy}px`;\n\n div.style.width = `${hitArea.width * wt.a * sx}px`;\n div.style.height = `${hitArea.height * wt.d * sy}px`;\n }\n else\n {\n hitArea = child.getBounds();\n\n this.capHitArea(hitArea);\n\n div.style.left = `${hitArea.x * sx}px`;\n div.style.top = `${hitArea.y * sy}px`;\n\n div.style.width = `${hitArea.width * sx}px`;\n div.style.height = `${hitArea.height * sy}px`;\n\n // update button titles and hints if they exist and they've changed\n if (div.title !== child.accessibleTitle && child.accessibleTitle !== null)\n {\n div.title = child.accessibleTitle;\n }\n if (div.getAttribute('aria-label') !== child.accessibleHint\n && child.accessibleHint !== null)\n {\n div.setAttribute('aria-label', child.accessibleHint);\n }\n }\n\n // the title or index may have changed, if so lets update it!\n if (child.accessibleTitle !== div.title || child.tabIndex !== div.tabIndex)\n {\n div.title = child.accessibleTitle;\n div.tabIndex = child.tabIndex;\n if (this.debug) this.updateDebugHTML(div);\n }\n }\n }\n\n // increment the render id..\n this.renderId++;\n }\n\n /**\n * private function that will visually add the information to the\n * accessability div\n * @param {HTMLElement} div -\n */\n public updateDebugHTML(div: IAccessibleHTMLElement): void\n {\n div.innerHTML = `type: ${div.type}</br> title : ${div.title}</br> tabIndex: ${div.tabIndex}`;\n }\n\n /**\n * Adjust the hit area based on the bounds of a display object\n * @param {PIXI.Rectangle} hitArea - Bounds of the child\n */\n public capHitArea(hitArea: Rectangle): void\n {\n if (hitArea.x < 0)\n {\n hitArea.width += hitArea.x;\n hitArea.x = 0;\n }\n\n if (hitArea.y < 0)\n {\n hitArea.height += hitArea.y;\n hitArea.y = 0;\n }\n\n const { width: viewWidth, height: viewHeight } = this.renderer;\n\n if (hitArea.x + hitArea.width > viewWidth)\n {\n hitArea.width = viewWidth - hitArea.x;\n }\n\n if (hitArea.y + hitArea.height > viewHeight)\n {\n hitArea.height = viewHeight - hitArea.y;\n }\n }\n\n /**\n * Adds a DisplayObject to the accessibility manager\n * @private\n * @param {PIXI.DisplayObject} displayObject - The child to make accessible.\n */\n private addChild<T extends DisplayObject>(displayObject: T): void\n {\n // this.activate();\n\n let div = this.pool.pop();\n\n if (!div)\n {\n div = document.createElement('button');\n\n div.style.width = `${DIV_TOUCH_SIZE}px`;\n div.style.height = `${DIV_TOUCH_SIZE}px`;\n div.style.backgroundColor = this.debug ? 'rgba(255,255,255,0.5)' : 'transparent';\n div.style.position = 'absolute';\n div.style.zIndex = DIV_TOUCH_ZINDEX.toString();\n div.style.borderStyle = 'none';\n\n // ARIA attributes ensure that button title and hint updates are announced properly\n if (navigator.userAgent.toLowerCase().includes('chrome'))\n {\n // Chrome doesn't need aria-live to work as intended; in fact it just gets more confused.\n div.setAttribute('aria-live', 'off');\n }\n else\n {\n div.setAttribute('aria-live', 'polite');\n }\n\n if (navigator.userAgent.match(/rv:.*Gecko\\//))\n {\n // FireFox needs this to announce only the new button name\n div.setAttribute('aria-relevant', 'additions');\n }\n else\n {\n // required by IE, other browsers don't much care\n div.setAttribute('aria-relevant', 'text');\n }\n\n div.addEventListener('click', this._onClick.bind(this));\n div.addEventListener('focus', this._onFocus.bind(this));\n div.addEventListener('focusout', this._onFocusOut.bind(this));\n }\n\n // set pointer events\n div.style.pointerEvents = displayObject.accessiblePointerEvents;\n // set the type, this defaults to button!\n div.type = displayObject.accessibleType;\n\n if (displayObject.accessibleTitle && displayObject.accessibleTitle !== null)\n {\n div.title = displayObject.accessibleTitle;\n }\n else if (!displayObject.accessibleHint\n || displayObject.accessibleHint === null)\n {\n div.title = `displayObject ${displayObject.tabIndex}`;\n }\n\n if (displayObject.accessibleHint\n && displayObject.accessibleHint !== null)\n {\n div.setAttribute('aria-label', displayObject.accessibleHint);\n }\n\n if (this.debug) this.updateDebugHTML(div);\n\n displayObject._accessibleActive = true;\n displayObject._accessibleDiv = div;\n div.displayObject = displayObject;\n\n this.children.push(displayObject);\n this.div.appendChild(displayObject._accessibleDiv);\n displayObject._accessibleDiv.tabIndex = displayObject.tabIndex;\n }\n\n /**\n * Dispatch events with the EventSystem.\n * @param e\n * @param type\n * @private\n */\n private _dispatchEvent(e: UIEvent, type: string[]): void\n {\n const { displayObject: target } = e.target as IAccessibleHTMLElement;\n const boundry = this.renderer.events.rootBoundary;\n const event: FederatedEvent = Object.assign(new FederatedEvent(boundry), { target });\n\n boundry.rootTarget = this.renderer.lastObjectRendered as DisplayObject;\n type.forEach((type) => boundry.dispatchEvent(event, type));\n }\n\n /**\n * Maps the div button press to pixi's EventSystem (click)\n * @private\n * @param {MouseEvent} e - The click event.\n */\n private _onClick(e: MouseEvent): void\n {\n this._dispatchEvent(e, ['click', 'pointertap', 'tap']);\n }\n\n /**\n * Maps the div focus events to pixi's EventSystem (mouseover)\n * @private\n * @param {FocusEvent} e - The focus event.\n */\n private _onFocus(e: FocusEvent): void\n {\n if (!(e.target as Element).getAttribute('aria-live'))\n {\n (e.target as Element).setAttribute('aria-live', 'assertive');\n }\n\n this._dispatchEvent(e, ['mouseover']);\n }\n\n /**\n * Maps the div focus events to pixi's EventSystem (mouseout)\n * @private\n * @param {FocusEvent} e - The focusout event.\n */\n private _onFocusOut(e: FocusEvent): void\n {\n if (!(e.target as Element).getAttribute('aria-live'))\n {\n (e.target as Element).setAttribute('aria-live', 'polite');\n }\n\n this._dispatchEvent(e, ['mouseout']);\n }\n\n /**\n * Is called when a key is pressed\n * @private\n * @param {KeyboardEvent} e - The keydown event.\n */\n private _onKeyDown(e: KeyboardEvent): void\n {\n if (e.keyCode !== KEY_CODE_TAB)\n {\n return;\n }\n\n this.activate();\n }\n\n /**\n * Is called when the mouse moves across the renderer element\n * @private\n * @param {MouseEvent} e - The mouse event.\n */\n private _onMouseMove(e: MouseEvent): void\n {\n if (e.movementX === 0 && e.movementY === 0)\n {\n return;\n }\n\n this.deactivate();\n }\n\n /** Destroys the accessibility manager */\n public destroy(): void\n {\n this.destroyTouchHook();\n this.div = null;\n\n globalThis.document.removeEventListener('mousemove', this._onMouseMove, true);\n globalThis.removeEventListener('keydown', this._onKeyDown);\n\n this.pool = null;\n this.children = null;\n this.renderer = null;\n }\n}\n\nextensions.add(AccessibilityManager);\n"],"names":["DisplayObject","accessibleTarget","utils","FederatedEvent","type","ExtensionType","extensions"],"mappings":"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"}
@@ -0,0 +1,197 @@
1
+ import { utils, ExtensionType, extensions } from "@pixi/core";
2
+ import { DisplayObject } from "@pixi/display";
3
+ import { FederatedEvent } from "@pixi/events";
4
+ import { accessibleTarget } from "./accessibleTarget.mjs";
5
+ DisplayObject.mixin(accessibleTarget);
6
+ const KEY_CODE_TAB = 9, DIV_TOUCH_SIZE = 100, DIV_TOUCH_POS_X = 0, DIV_TOUCH_POS_Y = 0, DIV_TOUCH_ZINDEX = 2, DIV_HOOK_SIZE = 1, DIV_HOOK_POS_X = -1e3, DIV_HOOK_POS_Y = -1e3, DIV_HOOK_ZINDEX = 2;
7
+ class AccessibilityManager {
8
+ // 2fps
9
+ /**
10
+ * @param {PIXI.CanvasRenderer|PIXI.Renderer} renderer - A reference to the current renderer
11
+ */
12
+ constructor(renderer) {
13
+ this.debug = !1, this._isActive = !1, this._isMobileAccessibility = !1, this.pool = [], this.renderId = 0, this.children = [], this.androidUpdateCount = 0, this.androidUpdateFrequency = 500, this._hookDiv = null, (utils.isMobile.tablet || utils.isMobile.phone) && this.createTouchHook();
14
+ const div = document.createElement("div");
15
+ div.style.width = `${DIV_TOUCH_SIZE}px`, div.style.height = `${DIV_TOUCH_SIZE}px`, div.style.position = "absolute", div.style.top = `${DIV_TOUCH_POS_X}px`, div.style.left = `${DIV_TOUCH_POS_Y}px`, div.style.zIndex = DIV_TOUCH_ZINDEX.toString(), this.div = div, this.renderer = renderer, this._onKeyDown = this._onKeyDown.bind(this), this._onMouseMove = this._onMouseMove.bind(this), globalThis.addEventListener("keydown", this._onKeyDown, !1);
16
+ }
17
+ /**
18
+ * Value of `true` if accessibility is currently active and accessibility layers are showing.
19
+ * @member {boolean}
20
+ * @readonly
21
+ */
22
+ get isActive() {
23
+ return this._isActive;
24
+ }
25
+ /**
26
+ * Value of `true` if accessibility is enabled for touch devices.
27
+ * @member {boolean}
28
+ * @readonly
29
+ */
30
+ get isMobileAccessibility() {
31
+ return this._isMobileAccessibility;
32
+ }
33
+ /**
34
+ * Creates the touch hooks.
35
+ * @private
36
+ */
37
+ createTouchHook() {
38
+ const hookDiv = document.createElement("button");
39
+ hookDiv.style.width = `${DIV_HOOK_SIZE}px`, hookDiv.style.height = `${DIV_HOOK_SIZE}px`, hookDiv.style.position = "absolute", hookDiv.style.top = `${DIV_HOOK_POS_X}px`, hookDiv.style.left = `${DIV_HOOK_POS_Y}px`, hookDiv.style.zIndex = DIV_HOOK_ZINDEX.toString(), hookDiv.style.backgroundColor = "#FF0000", hookDiv.title = "select to enable accessibility for this content", hookDiv.addEventListener("focus", () => {
40
+ this._isMobileAccessibility = !0, this.activate(), this.destroyTouchHook();
41
+ }), document.body.appendChild(hookDiv), this._hookDiv = hookDiv;
42
+ }
43
+ /**
44
+ * Destroys the touch hooks.
45
+ * @private
46
+ */
47
+ destroyTouchHook() {
48
+ this._hookDiv && (document.body.removeChild(this._hookDiv), this._hookDiv = null);
49
+ }
50
+ /**
51
+ * Activating will cause the Accessibility layer to be shown.
52
+ * This is called when a user presses the tab key.
53
+ * @private
54
+ */
55
+ activate() {
56
+ this._isActive || (this._isActive = !0, globalThis.document.addEventListener("mousemove", this._onMouseMove, !0), globalThis.removeEventListener("keydown", this._onKeyDown, !1), this.renderer.on("postrender", this.update, this), (this.renderer.view.parentNode || document.body)?.appendChild(this.div));
57
+ }
58
+ /**
59
+ * Deactivating will cause the Accessibility layer to be hidden.
60
+ * This is called when a user moves the mouse.
61
+ * @private
62
+ */
63
+ deactivate() {
64
+ !this._isActive || this._isMobileAccessibility || (this._isActive = !1, globalThis.document.removeEventListener("mousemove", this._onMouseMove, !0), globalThis.addEventListener("keydown", this._onKeyDown, !1), this.renderer.off("postrender", this.update), this.div.parentNode?.removeChild(this.div));
65
+ }
66
+ /**
67
+ * This recursive function will run through the scene graph and add any new accessible objects to the DOM layer.
68
+ * @private
69
+ * @param {PIXI.Container} displayObject - The DisplayObject to check.
70
+ */
71
+ updateAccessibleObjects(displayObject) {
72
+ if (!displayObject.visible || !displayObject.accessibleChildren)
73
+ return;
74
+ displayObject.accessible && displayObject.isInteractive() && (displayObject._accessibleActive || this.addChild(displayObject), displayObject.renderId = this.renderId);
75
+ const children = displayObject.children;
76
+ if (children)
77
+ for (let i = 0; i < children.length; i++)
78
+ this.updateAccessibleObjects(children[i]);
79
+ }
80
+ /**
81
+ * Before each render this function will ensure that all divs are mapped correctly to their DisplayObjects.
82
+ * @private
83
+ */
84
+ update() {
85
+ const now = performance.now();
86
+ if (utils.isMobile.android.device && now < this.androidUpdateCount || (this.androidUpdateCount = now + this.androidUpdateFrequency, !this.renderer.renderingToScreen))
87
+ return;
88
+ this.renderer.lastObjectRendered && this.updateAccessibleObjects(this.renderer.lastObjectRendered);
89
+ const { x, y, width, height } = this.renderer.view.getBoundingClientRect(), { width: viewWidth, height: viewHeight, resolution } = this.renderer, sx = width / viewWidth * resolution, sy = height / viewHeight * resolution;
90
+ let div = this.div;
91
+ div.style.left = `${x}px`, div.style.top = `${y}px`, div.style.width = `${viewWidth}px`, div.style.height = `${viewHeight}px`;
92
+ for (let i = 0; i < this.children.length; i++) {
93
+ const child = this.children[i];
94
+ if (child.renderId !== this.renderId)
95
+ child._accessibleActive = !1, utils.removeItems(this.children, i, 1), this.div.removeChild(child._accessibleDiv), this.pool.push(child._accessibleDiv), child._accessibleDiv = null, i--;
96
+ else {
97
+ div = child._accessibleDiv;
98
+ let hitArea = child.hitArea;
99
+ const wt = child.worldTransform;
100
+ child.hitArea ? (div.style.left = `${(wt.tx + hitArea.x * wt.a) * sx}px`, div.style.top = `${(wt.ty + hitArea.y * wt.d) * sy}px`, div.style.width = `${hitArea.width * wt.a * sx}px`, div.style.height = `${hitArea.height * wt.d * sy}px`) : (hitArea = child.getBounds(), this.capHitArea(hitArea), div.style.left = `${hitArea.x * sx}px`, div.style.top = `${hitArea.y * sy}px`, div.style.width = `${hitArea.width * sx}px`, div.style.height = `${hitArea.height * sy}px`, div.title !== child.accessibleTitle && child.accessibleTitle !== null && (div.title = child.accessibleTitle), div.getAttribute("aria-label") !== child.accessibleHint && child.accessibleHint !== null && div.setAttribute("aria-label", child.accessibleHint)), (child.accessibleTitle !== div.title || child.tabIndex !== div.tabIndex) && (div.title = child.accessibleTitle, div.tabIndex = child.tabIndex, this.debug && this.updateDebugHTML(div));
101
+ }
102
+ }
103
+ this.renderId++;
104
+ }
105
+ /**
106
+ * private function that will visually add the information to the
107
+ * accessability div
108
+ * @param {HTMLElement} div -
109
+ */
110
+ updateDebugHTML(div) {
111
+ div.innerHTML = `type: ${div.type}</br> title : ${div.title}</br> tabIndex: ${div.tabIndex}`;
112
+ }
113
+ /**
114
+ * Adjust the hit area based on the bounds of a display object
115
+ * @param {PIXI.Rectangle} hitArea - Bounds of the child
116
+ */
117
+ capHitArea(hitArea) {
118
+ hitArea.x < 0 && (hitArea.width += hitArea.x, hitArea.x = 0), hitArea.y < 0 && (hitArea.height += hitArea.y, hitArea.y = 0);
119
+ const { width: viewWidth, height: viewHeight } = this.renderer;
120
+ hitArea.x + hitArea.width > viewWidth && (hitArea.width = viewWidth - hitArea.x), hitArea.y + hitArea.height > viewHeight && (hitArea.height = viewHeight - hitArea.y);
121
+ }
122
+ /**
123
+ * Adds a DisplayObject to the accessibility manager
124
+ * @private
125
+ * @param {PIXI.DisplayObject} displayObject - The child to make accessible.
126
+ */
127
+ addChild(displayObject) {
128
+ let div = this.pool.pop();
129
+ div || (div = document.createElement("button"), div.style.width = `${DIV_TOUCH_SIZE}px`, div.style.height = `${DIV_TOUCH_SIZE}px`, div.style.backgroundColor = this.debug ? "rgba(255,255,255,0.5)" : "transparent", div.style.position = "absolute", div.style.zIndex = DIV_TOUCH_ZINDEX.toString(), div.style.borderStyle = "none", navigator.userAgent.toLowerCase().includes("chrome") ? div.setAttribute("aria-live", "off") : div.setAttribute("aria-live", "polite"), navigator.userAgent.match(/rv:.*Gecko\//) ? div.setAttribute("aria-relevant", "additions") : div.setAttribute("aria-relevant", "text"), div.addEventListener("click", this._onClick.bind(this)), div.addEventListener("focus", this._onFocus.bind(this)), div.addEventListener("focusout", this._onFocusOut.bind(this))), div.style.pointerEvents = displayObject.accessiblePointerEvents, div.type = displayObject.accessibleType, displayObject.accessibleTitle && displayObject.accessibleTitle !== null ? div.title = displayObject.accessibleTitle : (!displayObject.accessibleHint || displayObject.accessibleHint === null) && (div.title = `displayObject ${displayObject.tabIndex}`), displayObject.accessibleHint && displayObject.accessibleHint !== null && div.setAttribute("aria-label", displayObject.accessibleHint), this.debug && this.updateDebugHTML(div), displayObject._accessibleActive = !0, displayObject._accessibleDiv = div, div.displayObject = displayObject, this.children.push(displayObject), this.div.appendChild(displayObject._accessibleDiv), displayObject._accessibleDiv.tabIndex = displayObject.tabIndex;
130
+ }
131
+ /**
132
+ * Dispatch events with the EventSystem.
133
+ * @param e
134
+ * @param type
135
+ * @private
136
+ */
137
+ _dispatchEvent(e, type) {
138
+ const { displayObject: target } = e.target, boundry = this.renderer.events.rootBoundary, event = Object.assign(new FederatedEvent(boundry), { target });
139
+ boundry.rootTarget = this.renderer.lastObjectRendered, type.forEach((type2) => boundry.dispatchEvent(event, type2));
140
+ }
141
+ /**
142
+ * Maps the div button press to pixi's EventSystem (click)
143
+ * @private
144
+ * @param {MouseEvent} e - The click event.
145
+ */
146
+ _onClick(e) {
147
+ this._dispatchEvent(e, ["click", "pointertap", "tap"]);
148
+ }
149
+ /**
150
+ * Maps the div focus events to pixi's EventSystem (mouseover)
151
+ * @private
152
+ * @param {FocusEvent} e - The focus event.
153
+ */
154
+ _onFocus(e) {
155
+ e.target.getAttribute("aria-live") || e.target.setAttribute("aria-live", "assertive"), this._dispatchEvent(e, ["mouseover"]);
156
+ }
157
+ /**
158
+ * Maps the div focus events to pixi's EventSystem (mouseout)
159
+ * @private
160
+ * @param {FocusEvent} e - The focusout event.
161
+ */
162
+ _onFocusOut(e) {
163
+ e.target.getAttribute("aria-live") || e.target.setAttribute("aria-live", "polite"), this._dispatchEvent(e, ["mouseout"]);
164
+ }
165
+ /**
166
+ * Is called when a key is pressed
167
+ * @private
168
+ * @param {KeyboardEvent} e - The keydown event.
169
+ */
170
+ _onKeyDown(e) {
171
+ e.keyCode === KEY_CODE_TAB && this.activate();
172
+ }
173
+ /**
174
+ * Is called when the mouse moves across the renderer element
175
+ * @private
176
+ * @param {MouseEvent} e - The mouse event.
177
+ */
178
+ _onMouseMove(e) {
179
+ e.movementX === 0 && e.movementY === 0 || this.deactivate();
180
+ }
181
+ /** Destroys the accessibility manager */
182
+ destroy() {
183
+ this.destroyTouchHook(), this.div = null, globalThis.document.removeEventListener("mousemove", this._onMouseMove, !0), globalThis.removeEventListener("keydown", this._onKeyDown), this.pool = null, this.children = null, this.renderer = null;
184
+ }
185
+ }
186
+ AccessibilityManager.extension = {
187
+ name: "accessibility",
188
+ type: [
189
+ ExtensionType.RendererPlugin,
190
+ ExtensionType.CanvasRendererPlugin
191
+ ]
192
+ };
193
+ extensions.add(AccessibilityManager);
194
+ export {
195
+ AccessibilityManager
196
+ };
197
+ //# sourceMappingURL=AccessibilityManager.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccessibilityManager.mjs","sources":["../src/AccessibilityManager.ts"],"sourcesContent":["import { extensions, ExtensionType, utils } from '@pixi/core';\nimport { DisplayObject } from '@pixi/display';\nimport { FederatedEvent } from '@pixi/events';\nimport { accessibleTarget } from './accessibleTarget';\n\nimport type { ExtensionMetadata, IRenderer, Rectangle } from '@pixi/core';\nimport type { Container } from '@pixi/display';\nimport type { IAccessibleHTMLElement } from './accessibleTarget';\n\n// add some extra variables to the container..\nDisplayObject.mixin(accessibleTarget);\n\nconst KEY_CODE_TAB = 9;\n\nconst DIV_TOUCH_SIZE = 100;\nconst DIV_TOUCH_POS_X = 0;\nconst DIV_TOUCH_POS_Y = 0;\nconst DIV_TOUCH_ZINDEX = 2;\n\nconst DIV_HOOK_SIZE = 1;\nconst DIV_HOOK_POS_X = -1000;\nconst DIV_HOOK_POS_Y = -1000;\nconst DIV_HOOK_ZINDEX = 2;\n\n/**\n * The Accessibility manager recreates the ability to tab and have content read by screen readers.\n * This is very important as it can possibly help people with disabilities access PixiJS content.\n *\n * A DisplayObject can be made accessible just like it can be made interactive. This manager will map the\n * events as if the mouse was being used, minimizing the effort required to implement.\n *\n * An instance of this class is automatically created by default, and can be found at `renderer.plugins.accessibility`\n * @class\n * @memberof PIXI\n */\nexport class AccessibilityManager\n{\n /** @ignore */\n static extension: ExtensionMetadata = {\n name: 'accessibility',\n type: [\n ExtensionType.RendererPlugin,\n ExtensionType.CanvasRendererPlugin,\n ],\n };\n\n /** Setting this to true will visually show the divs. */\n public debug = false;\n\n /**\n * The renderer this accessibility manager works for.\n * @type {PIXI.CanvasRenderer|PIXI.Renderer}\n */\n public renderer: IRenderer;\n\n /** Internal variable, see isActive getter. */\n private _isActive = false;\n\n /** Internal variable, see isMobileAccessibility getter. */\n private _isMobileAccessibility = false;\n\n /** Button element for handling touch hooks. */\n private _hookDiv: HTMLElement;\n\n /** This is the dom element that will sit over the PixiJS element. This is where the div overlays will go. */\n private div: HTMLElement;\n\n /** A simple pool for storing divs. */\n private pool: IAccessibleHTMLElement[] = [];\n\n /** This is a tick used to check if an object is no longer being rendered. */\n private renderId = 0;\n\n /** The array of currently active accessible items. */\n private children: DisplayObject[] = [];\n\n /** Count to throttle div updates on android devices. */\n private androidUpdateCount = 0;\n\n /** The frequency to update the div elements. */\n private androidUpdateFrequency = 500; // 2fps\n\n /**\n * @param {PIXI.CanvasRenderer|PIXI.Renderer} renderer - A reference to the current renderer\n */\n constructor(renderer: IRenderer)\n {\n this._hookDiv = null;\n\n if (utils.isMobile.tablet || utils.isMobile.phone)\n {\n this.createTouchHook();\n }\n\n // first we create a div that will sit over the PixiJS element. This is where the div overlays will go.\n const div = document.createElement('div');\n\n div.style.width = `${DIV_TOUCH_SIZE}px`;\n div.style.height = `${DIV_TOUCH_SIZE}px`;\n div.style.position = 'absolute';\n div.style.top = `${DIV_TOUCH_POS_X}px`;\n div.style.left = `${DIV_TOUCH_POS_Y}px`;\n div.style.zIndex = DIV_TOUCH_ZINDEX.toString();\n\n this.div = div;\n this.renderer = renderer;\n\n /**\n * pre-bind the functions\n * @type {Function}\n * @private\n */\n this._onKeyDown = this._onKeyDown.bind(this);\n\n /**\n * pre-bind the functions\n * @type {Function}\n * @private\n */\n this._onMouseMove = this._onMouseMove.bind(this);\n\n // let listen for tab.. once pressed we can fire up and show the accessibility layer\n globalThis.addEventListener('keydown', this._onKeyDown, false);\n }\n\n /**\n * Value of `true` if accessibility is currently active and accessibility layers are showing.\n * @member {boolean}\n * @readonly\n */\n get isActive(): boolean\n {\n return this._isActive;\n }\n\n /**\n * Value of `true` if accessibility is enabled for touch devices.\n * @member {boolean}\n * @readonly\n */\n get isMobileAccessibility(): boolean\n {\n return this._isMobileAccessibility;\n }\n\n /**\n * Creates the touch hooks.\n * @private\n */\n private createTouchHook(): void\n {\n const hookDiv = document.createElement('button');\n\n hookDiv.style.width = `${DIV_HOOK_SIZE}px`;\n hookDiv.style.height = `${DIV_HOOK_SIZE}px`;\n hookDiv.style.position = 'absolute';\n hookDiv.style.top = `${DIV_HOOK_POS_X}px`;\n hookDiv.style.left = `${DIV_HOOK_POS_Y}px`;\n hookDiv.style.zIndex = DIV_HOOK_ZINDEX.toString();\n hookDiv.style.backgroundColor = '#FF0000';\n hookDiv.title = 'select to enable accessibility for this content';\n\n hookDiv.addEventListener('focus', () =>\n {\n this._isMobileAccessibility = true;\n this.activate();\n this.destroyTouchHook();\n });\n\n document.body.appendChild(hookDiv);\n this._hookDiv = hookDiv;\n }\n\n /**\n * Destroys the touch hooks.\n * @private\n */\n private destroyTouchHook(): void\n {\n if (!this._hookDiv)\n {\n return;\n }\n document.body.removeChild(this._hookDiv);\n this._hookDiv = null;\n }\n\n /**\n * Activating will cause the Accessibility layer to be shown.\n * This is called when a user presses the tab key.\n * @private\n */\n private activate(): void\n {\n if (this._isActive)\n {\n return;\n }\n\n this._isActive = true;\n\n globalThis.document.addEventListener('mousemove', this._onMouseMove, true);\n globalThis.removeEventListener('keydown', this._onKeyDown, false);\n\n this.renderer.on('postrender', this.update, this);\n this.renderer.view.parentNode?.appendChild(this.div);\n }\n\n /**\n * Deactivating will cause the Accessibility layer to be hidden.\n * This is called when a user moves the mouse.\n * @private\n */\n private deactivate(): void\n {\n if (!this._isActive || this._isMobileAccessibility)\n {\n return;\n }\n\n this._isActive = false;\n\n globalThis.document.removeEventListener('mousemove', this._onMouseMove, true);\n globalThis.addEventListener('keydown', this._onKeyDown, false);\n\n this.renderer.off('postrender', this.update);\n this.div.parentNode?.removeChild(this.div);\n }\n\n /**\n * This recursive function will run through the scene graph and add any new accessible objects to the DOM layer.\n * @private\n * @param {PIXI.Container} displayObject - The DisplayObject to check.\n */\n private updateAccessibleObjects(displayObject: Container): void\n {\n if (!displayObject.visible || !displayObject.accessibleChildren)\n {\n return;\n }\n\n if (displayObject.accessible && displayObject.isInteractive())\n {\n if (!displayObject._accessibleActive)\n {\n this.addChild(displayObject);\n }\n\n displayObject.renderId = this.renderId;\n }\n\n const children = displayObject.children;\n\n if (children)\n {\n for (let i = 0; i < children.length; i++)\n {\n this.updateAccessibleObjects(children[i] as Container);\n }\n }\n }\n\n /**\n * Before each render this function will ensure that all divs are mapped correctly to their DisplayObjects.\n * @private\n */\n private update(): void\n {\n /* On Android default web browser, tab order seems to be calculated by position rather than tabIndex,\n * moving buttons can cause focus to flicker between two buttons making it hard/impossible to navigate,\n * so I am just running update every half a second, seems to fix it.\n */\n const now = performance.now();\n\n if (utils.isMobile.android.device && now < this.androidUpdateCount)\n {\n return;\n }\n\n this.androidUpdateCount = now + this.androidUpdateFrequency;\n\n if (!this.renderer.renderingToScreen)\n {\n return;\n }\n\n // update children...\n if (this.renderer.lastObjectRendered)\n {\n this.updateAccessibleObjects(this.renderer.lastObjectRendered as Container);\n }\n\n const { x, y, width, height } = this.renderer.view.getBoundingClientRect();\n const { width: viewWidth, height: viewHeight, resolution } = this.renderer;\n\n const sx = (width / viewWidth) * resolution;\n const sy = (height / viewHeight) * resolution;\n\n let div = this.div;\n\n div.style.left = `${x}px`;\n div.style.top = `${y}px`;\n div.style.width = `${viewWidth}px`;\n div.style.height = `${viewHeight}px`;\n\n for (let i = 0; i < this.children.length; i++)\n {\n const child = this.children[i];\n\n if (child.renderId !== this.renderId)\n {\n child._accessibleActive = false;\n\n utils.removeItems(this.children, i, 1);\n this.div.removeChild(child._accessibleDiv);\n this.pool.push(child._accessibleDiv);\n child._accessibleDiv = null;\n\n i--;\n }\n else\n {\n // map div to display..\n div = child._accessibleDiv;\n let hitArea = child.hitArea as Rectangle;\n const wt = child.worldTransform;\n\n if (child.hitArea)\n {\n div.style.left = `${(wt.tx + (hitArea.x * wt.a)) * sx}px`;\n div.style.top = `${(wt.ty + (hitArea.y * wt.d)) * sy}px`;\n\n div.style.width = `${hitArea.width * wt.a * sx}px`;\n div.style.height = `${hitArea.height * wt.d * sy}px`;\n }\n else\n {\n hitArea = child.getBounds();\n\n this.capHitArea(hitArea);\n\n div.style.left = `${hitArea.x * sx}px`;\n div.style.top = `${hitArea.y * sy}px`;\n\n div.style.width = `${hitArea.width * sx}px`;\n div.style.height = `${hitArea.height * sy}px`;\n\n // update button titles and hints if they exist and they've changed\n if (div.title !== child.accessibleTitle && child.accessibleTitle !== null)\n {\n div.title = child.accessibleTitle;\n }\n if (div.getAttribute('aria-label') !== child.accessibleHint\n && child.accessibleHint !== null)\n {\n div.setAttribute('aria-label', child.accessibleHint);\n }\n }\n\n // the title or index may have changed, if so lets update it!\n if (child.accessibleTitle !== div.title || child.tabIndex !== div.tabIndex)\n {\n div.title = child.accessibleTitle;\n div.tabIndex = child.tabIndex;\n if (this.debug) this.updateDebugHTML(div);\n }\n }\n }\n\n // increment the render id..\n this.renderId++;\n }\n\n /**\n * private function that will visually add the information to the\n * accessability div\n * @param {HTMLElement} div -\n */\n public updateDebugHTML(div: IAccessibleHTMLElement): void\n {\n div.innerHTML = `type: ${div.type}</br> title : ${div.title}</br> tabIndex: ${div.tabIndex}`;\n }\n\n /**\n * Adjust the hit area based on the bounds of a display object\n * @param {PIXI.Rectangle} hitArea - Bounds of the child\n */\n public capHitArea(hitArea: Rectangle): void\n {\n if (hitArea.x < 0)\n {\n hitArea.width += hitArea.x;\n hitArea.x = 0;\n }\n\n if (hitArea.y < 0)\n {\n hitArea.height += hitArea.y;\n hitArea.y = 0;\n }\n\n const { width: viewWidth, height: viewHeight } = this.renderer;\n\n if (hitArea.x + hitArea.width > viewWidth)\n {\n hitArea.width = viewWidth - hitArea.x;\n }\n\n if (hitArea.y + hitArea.height > viewHeight)\n {\n hitArea.height = viewHeight - hitArea.y;\n }\n }\n\n /**\n * Adds a DisplayObject to the accessibility manager\n * @private\n * @param {PIXI.DisplayObject} displayObject - The child to make accessible.\n */\n private addChild<T extends DisplayObject>(displayObject: T): void\n {\n // this.activate();\n\n let div = this.pool.pop();\n\n if (!div)\n {\n div = document.createElement('button');\n\n div.style.width = `${DIV_TOUCH_SIZE}px`;\n div.style.height = `${DIV_TOUCH_SIZE}px`;\n div.style.backgroundColor = this.debug ? 'rgba(255,255,255,0.5)' : 'transparent';\n div.style.position = 'absolute';\n div.style.zIndex = DIV_TOUCH_ZINDEX.toString();\n div.style.borderStyle = 'none';\n\n // ARIA attributes ensure that button title and hint updates are announced properly\n if (navigator.userAgent.toLowerCase().includes('chrome'))\n {\n // Chrome doesn't need aria-live to work as intended; in fact it just gets more confused.\n div.setAttribute('aria-live', 'off');\n }\n else\n {\n div.setAttribute('aria-live', 'polite');\n }\n\n if (navigator.userAgent.match(/rv:.*Gecko\\//))\n {\n // FireFox needs this to announce only the new button name\n div.setAttribute('aria-relevant', 'additions');\n }\n else\n {\n // required by IE, other browsers don't much care\n div.setAttribute('aria-relevant', 'text');\n }\n\n div.addEventListener('click', this._onClick.bind(this));\n div.addEventListener('focus', this._onFocus.bind(this));\n div.addEventListener('focusout', this._onFocusOut.bind(this));\n }\n\n // set pointer events\n div.style.pointerEvents = displayObject.accessiblePointerEvents;\n // set the type, this defaults to button!\n div.type = displayObject.accessibleType;\n\n if (displayObject.accessibleTitle && displayObject.accessibleTitle !== null)\n {\n div.title = displayObject.accessibleTitle;\n }\n else if (!displayObject.accessibleHint\n || displayObject.accessibleHint === null)\n {\n div.title = `displayObject ${displayObject.tabIndex}`;\n }\n\n if (displayObject.accessibleHint\n && displayObject.accessibleHint !== null)\n {\n div.setAttribute('aria-label', displayObject.accessibleHint);\n }\n\n if (this.debug) this.updateDebugHTML(div);\n\n displayObject._accessibleActive = true;\n displayObject._accessibleDiv = div;\n div.displayObject = displayObject;\n\n this.children.push(displayObject);\n this.div.appendChild(displayObject._accessibleDiv);\n displayObject._accessibleDiv.tabIndex = displayObject.tabIndex;\n }\n\n /**\n * Dispatch events with the EventSystem.\n * @param e\n * @param type\n * @private\n */\n private _dispatchEvent(e: UIEvent, type: string[]): void\n {\n const { displayObject: target } = e.target as IAccessibleHTMLElement;\n const boundry = this.renderer.events.rootBoundary;\n const event: FederatedEvent = Object.assign(new FederatedEvent(boundry), { target });\n\n boundry.rootTarget = this.renderer.lastObjectRendered as DisplayObject;\n type.forEach((type) => boundry.dispatchEvent(event, type));\n }\n\n /**\n * Maps the div button press to pixi's EventSystem (click)\n * @private\n * @param {MouseEvent} e - The click event.\n */\n private _onClick(e: MouseEvent): void\n {\n this._dispatchEvent(e, ['click', 'pointertap', 'tap']);\n }\n\n /**\n * Maps the div focus events to pixi's EventSystem (mouseover)\n * @private\n * @param {FocusEvent} e - The focus event.\n */\n private _onFocus(e: FocusEvent): void\n {\n if (!(e.target as Element).getAttribute('aria-live'))\n {\n (e.target as Element).setAttribute('aria-live', 'assertive');\n }\n\n this._dispatchEvent(e, ['mouseover']);\n }\n\n /**\n * Maps the div focus events to pixi's EventSystem (mouseout)\n * @private\n * @param {FocusEvent} e - The focusout event.\n */\n private _onFocusOut(e: FocusEvent): void\n {\n if (!(e.target as Element).getAttribute('aria-live'))\n {\n (e.target as Element).setAttribute('aria-live', 'polite');\n }\n\n this._dispatchEvent(e, ['mouseout']);\n }\n\n /**\n * Is called when a key is pressed\n * @private\n * @param {KeyboardEvent} e - The keydown event.\n */\n private _onKeyDown(e: KeyboardEvent): void\n {\n if (e.keyCode !== KEY_CODE_TAB)\n {\n return;\n }\n\n this.activate();\n }\n\n /**\n * Is called when the mouse moves across the renderer element\n * @private\n * @param {MouseEvent} e - The mouse event.\n */\n private _onMouseMove(e: MouseEvent): void\n {\n if (e.movementX === 0 && e.movementY === 0)\n {\n return;\n }\n\n this.deactivate();\n }\n\n /** Destroys the accessibility manager */\n public destroy(): void\n {\n this.destroyTouchHook();\n this.div = null;\n\n globalThis.document.removeEventListener('mousemove', this._onMouseMove, true);\n globalThis.removeEventListener('keydown', this._onKeyDown);\n\n this.pool = null;\n this.children = null;\n this.renderer = null;\n }\n}\n\nextensions.add(AccessibilityManager);\n"],"names":["type"],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { DisplayObject } from '@pixi/display';
2
+ export type PointerEvents = 'auto' | 'none' | 'visiblePainted' | 'visibleFill' | 'visibleStroke' | 'visible' | 'painted' | 'fill' | 'stroke' | 'all' | 'inherit';
3
+ export interface IAccessibleTarget {
4
+ accessible: boolean;
5
+ accessibleTitle: string;
6
+ accessibleHint: string;
7
+ tabIndex: number;
8
+ _accessibleActive: boolean;
9
+ _accessibleDiv: IAccessibleHTMLElement;
10
+ accessibleType: string;
11
+ accessiblePointerEvents: PointerEvents;
12
+ accessibleChildren: boolean;
13
+ renderId: number;
14
+ }
15
+ export interface IAccessibleHTMLElement extends HTMLElement {
16
+ type?: string;
17
+ displayObject?: DisplayObject;
18
+ }
19
+ /**
20
+ * Default property values of accessible objects
21
+ * used by {@link PIXI.AccessibilityManager}.
22
+ * @private
23
+ * @function accessibleTarget
24
+ * @memberof PIXI
25
+ * @type {object}
26
+ * @example
27
+ * import { accessibleTarget } from 'pixi.js';
28
+ *
29
+ * function MyObject() {}
30
+ * Object.assign(MyObject.prototype, accessibleTarget);
31
+ */
32
+ export declare const accessibleTarget: IAccessibleTarget;
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ const accessibleTarget = {
3
+ /**
4
+ * Flag for if the object is accessible. If true AccessibilityManager will overlay a
5
+ * shadow div with attributes set
6
+ * @member {boolean}
7
+ * @memberof PIXI.DisplayObject#
8
+ */
9
+ accessible: !1,
10
+ /**
11
+ * Sets the title attribute of the shadow div
12
+ * If accessibleTitle AND accessibleHint has not been this will default to 'displayObject [tabIndex]'
13
+ * @member {?string}
14
+ * @memberof PIXI.DisplayObject#
15
+ */
16
+ accessibleTitle: null,
17
+ /**
18
+ * Sets the aria-label attribute of the shadow div
19
+ * @member {string}
20
+ * @memberof PIXI.DisplayObject#
21
+ */
22
+ accessibleHint: null,
23
+ /**
24
+ * @member {number}
25
+ * @memberof PIXI.DisplayObject#
26
+ * @private
27
+ * @todo Needs docs.
28
+ */
29
+ tabIndex: 0,
30
+ /**
31
+ * @member {boolean}
32
+ * @memberof PIXI.DisplayObject#
33
+ * @todo Needs docs.
34
+ */
35
+ _accessibleActive: !1,
36
+ /**
37
+ * @member {boolean}
38
+ * @memberof PIXI.DisplayObject#
39
+ * @todo Needs docs.
40
+ */
41
+ _accessibleDiv: null,
42
+ /**
43
+ * Specify the type of div the accessible layer is. Screen readers treat the element differently
44
+ * depending on this type. Defaults to button.
45
+ * @member {string}
46
+ * @memberof PIXI.DisplayObject#
47
+ * @default 'button'
48
+ */
49
+ accessibleType: "button",
50
+ /**
51
+ * Specify the pointer-events the accessible div will use
52
+ * Defaults to auto.
53
+ * @member {string}
54
+ * @memberof PIXI.DisplayObject#
55
+ * @default 'auto'
56
+ */
57
+ accessiblePointerEvents: "auto",
58
+ /**
59
+ * Setting to false will prevent any children inside this container to
60
+ * be accessible. Defaults to true.
61
+ * @member {boolean}
62
+ * @memberof PIXI.DisplayObject#
63
+ * @default true
64
+ */
65
+ accessibleChildren: !0,
66
+ renderId: -1
67
+ };
68
+ exports.accessibleTarget = accessibleTarget;
69
+ //# sourceMappingURL=accessibleTarget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accessibleTarget.js","sources":["../src/accessibleTarget.ts"],"sourcesContent":["import type { DisplayObject } from '@pixi/display';\n\nexport type PointerEvents = 'auto'\n| 'none'\n| 'visiblePainted'\n| 'visibleFill'\n| 'visibleStroke'\n| 'visible'\n| 'painted'\n| 'fill'\n| 'stroke'\n| 'all'\n| 'inherit';\n\nexport interface IAccessibleTarget\n{\n accessible: boolean;\n accessibleTitle: string;\n accessibleHint: string;\n tabIndex: number;\n _accessibleActive: boolean;\n _accessibleDiv: IAccessibleHTMLElement;\n accessibleType: string;\n accessiblePointerEvents: PointerEvents;\n accessibleChildren: boolean;\n renderId: number;\n}\n\nexport interface IAccessibleHTMLElement extends HTMLElement\n{\n type?: string;\n displayObject?: DisplayObject;\n}\n\n/**\n * Default property values of accessible objects\n * used by {@link PIXI.AccessibilityManager}.\n * @private\n * @function accessibleTarget\n * @memberof PIXI\n * @type {object}\n * @example\n * import { accessibleTarget } from 'pixi.js';\n *\n * function MyObject() {}\n * Object.assign(MyObject.prototype, accessibleTarget);\n */\nexport const accessibleTarget: IAccessibleTarget = {\n /**\n * Flag for if the object is accessible. If true AccessibilityManager will overlay a\n * shadow div with attributes set\n * @member {boolean}\n * @memberof PIXI.DisplayObject#\n */\n accessible: false,\n\n /**\n * Sets the title attribute of the shadow div\n * If accessibleTitle AND accessibleHint has not been this will default to 'displayObject [tabIndex]'\n * @member {?string}\n * @memberof PIXI.DisplayObject#\n */\n accessibleTitle: null,\n\n /**\n * Sets the aria-label attribute of the shadow div\n * @member {string}\n * @memberof PIXI.DisplayObject#\n */\n accessibleHint: null,\n\n /**\n * @member {number}\n * @memberof PIXI.DisplayObject#\n * @private\n * @todo Needs docs.\n */\n tabIndex: 0,\n\n /**\n * @member {boolean}\n * @memberof PIXI.DisplayObject#\n * @todo Needs docs.\n */\n _accessibleActive: false,\n\n /**\n * @member {boolean}\n * @memberof PIXI.DisplayObject#\n * @todo Needs docs.\n */\n _accessibleDiv: null,\n\n /**\n * Specify the type of div the accessible layer is. Screen readers treat the element differently\n * depending on this type. Defaults to button.\n * @member {string}\n * @memberof PIXI.DisplayObject#\n * @default 'button'\n */\n accessibleType: 'button',\n\n /**\n * Specify the pointer-events the accessible div will use\n * Defaults to auto.\n * @member {string}\n * @memberof PIXI.DisplayObject#\n * @default 'auto'\n */\n accessiblePointerEvents: 'auto',\n\n /**\n * Setting to false will prevent any children inside this container to\n * be accessible. Defaults to true.\n * @member {boolean}\n * @memberof PIXI.DisplayObject#\n * @default true\n */\n accessibleChildren: true,\n\n renderId: -1,\n};\n"],"names":[],"mappings":";AA+CO,MAAM,mBAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO/C,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQZ,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOjB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQhB,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOV,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOnB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAShB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAShB,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASzB,oBAAoB;AAAA,EAEpB,UAAU;AACd;;"}
@@ -0,0 +1,70 @@
1
+ const accessibleTarget = {
2
+ /**
3
+ * Flag for if the object is accessible. If true AccessibilityManager will overlay a
4
+ * shadow div with attributes set
5
+ * @member {boolean}
6
+ * @memberof PIXI.DisplayObject#
7
+ */
8
+ accessible: !1,
9
+ /**
10
+ * Sets the title attribute of the shadow div
11
+ * If accessibleTitle AND accessibleHint has not been this will default to 'displayObject [tabIndex]'
12
+ * @member {?string}
13
+ * @memberof PIXI.DisplayObject#
14
+ */
15
+ accessibleTitle: null,
16
+ /**
17
+ * Sets the aria-label attribute of the shadow div
18
+ * @member {string}
19
+ * @memberof PIXI.DisplayObject#
20
+ */
21
+ accessibleHint: null,
22
+ /**
23
+ * @member {number}
24
+ * @memberof PIXI.DisplayObject#
25
+ * @private
26
+ * @todo Needs docs.
27
+ */
28
+ tabIndex: 0,
29
+ /**
30
+ * @member {boolean}
31
+ * @memberof PIXI.DisplayObject#
32
+ * @todo Needs docs.
33
+ */
34
+ _accessibleActive: !1,
35
+ /**
36
+ * @member {boolean}
37
+ * @memberof PIXI.DisplayObject#
38
+ * @todo Needs docs.
39
+ */
40
+ _accessibleDiv: null,
41
+ /**
42
+ * Specify the type of div the accessible layer is. Screen readers treat the element differently
43
+ * depending on this type. Defaults to button.
44
+ * @member {string}
45
+ * @memberof PIXI.DisplayObject#
46
+ * @default 'button'
47
+ */
48
+ accessibleType: "button",
49
+ /**
50
+ * Specify the pointer-events the accessible div will use
51
+ * Defaults to auto.
52
+ * @member {string}
53
+ * @memberof PIXI.DisplayObject#
54
+ * @default 'auto'
55
+ */
56
+ accessiblePointerEvents: "auto",
57
+ /**
58
+ * Setting to false will prevent any children inside this container to
59
+ * be accessible. Defaults to true.
60
+ * @member {boolean}
61
+ * @memberof PIXI.DisplayObject#
62
+ * @default true
63
+ */
64
+ accessibleChildren: !0,
65
+ renderId: -1
66
+ };
67
+ export {
68
+ accessibleTarget
69
+ };
70
+ //# sourceMappingURL=accessibleTarget.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accessibleTarget.mjs","sources":["../src/accessibleTarget.ts"],"sourcesContent":["import type { DisplayObject } from '@pixi/display';\n\nexport type PointerEvents = 'auto'\n| 'none'\n| 'visiblePainted'\n| 'visibleFill'\n| 'visibleStroke'\n| 'visible'\n| 'painted'\n| 'fill'\n| 'stroke'\n| 'all'\n| 'inherit';\n\nexport interface IAccessibleTarget\n{\n accessible: boolean;\n accessibleTitle: string;\n accessibleHint: string;\n tabIndex: number;\n _accessibleActive: boolean;\n _accessibleDiv: IAccessibleHTMLElement;\n accessibleType: string;\n accessiblePointerEvents: PointerEvents;\n accessibleChildren: boolean;\n renderId: number;\n}\n\nexport interface IAccessibleHTMLElement extends HTMLElement\n{\n type?: string;\n displayObject?: DisplayObject;\n}\n\n/**\n * Default property values of accessible objects\n * used by {@link PIXI.AccessibilityManager}.\n * @private\n * @function accessibleTarget\n * @memberof PIXI\n * @type {object}\n * @example\n * import { accessibleTarget } from 'pixi.js';\n *\n * function MyObject() {}\n * Object.assign(MyObject.prototype, accessibleTarget);\n */\nexport const accessibleTarget: IAccessibleTarget = {\n /**\n * Flag for if the object is accessible. If true AccessibilityManager will overlay a\n * shadow div with attributes set\n * @member {boolean}\n * @memberof PIXI.DisplayObject#\n */\n accessible: false,\n\n /**\n * Sets the title attribute of the shadow div\n * If accessibleTitle AND accessibleHint has not been this will default to 'displayObject [tabIndex]'\n * @member {?string}\n * @memberof PIXI.DisplayObject#\n */\n accessibleTitle: null,\n\n /**\n * Sets the aria-label attribute of the shadow div\n * @member {string}\n * @memberof PIXI.DisplayObject#\n */\n accessibleHint: null,\n\n /**\n * @member {number}\n * @memberof PIXI.DisplayObject#\n * @private\n * @todo Needs docs.\n */\n tabIndex: 0,\n\n /**\n * @member {boolean}\n * @memberof PIXI.DisplayObject#\n * @todo Needs docs.\n */\n _accessibleActive: false,\n\n /**\n * @member {boolean}\n * @memberof PIXI.DisplayObject#\n * @todo Needs docs.\n */\n _accessibleDiv: null,\n\n /**\n * Specify the type of div the accessible layer is. Screen readers treat the element differently\n * depending on this type. Defaults to button.\n * @member {string}\n * @memberof PIXI.DisplayObject#\n * @default 'button'\n */\n accessibleType: 'button',\n\n /**\n * Specify the pointer-events the accessible div will use\n * Defaults to auto.\n * @member {string}\n * @memberof PIXI.DisplayObject#\n * @default 'auto'\n */\n accessiblePointerEvents: 'auto',\n\n /**\n * Setting to false will prevent any children inside this container to\n * be accessible. Defaults to true.\n * @member {boolean}\n * @memberof PIXI.DisplayObject#\n * @default true\n */\n accessibleChildren: true,\n\n renderId: -1,\n};\n"],"names":[],"mappings":"AA+CO,MAAM,mBAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO/C,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQZ,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOjB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQhB,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOV,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOnB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAShB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAShB,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASzB,oBAAoB;AAAA,EAEpB,UAAU;AACd;"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ /// <reference path="../global.d.ts" />
2
+ export * from './AccessibilityManager';
3
+ export * from './accessibleTarget';
package/lib/index.js ADDED
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ // ---------------------------------------------------------------------------
3
+ // HarmonyOS / Node.js runtime adaptation
4
+ //
5
+ // AccessibilityManager operates on a real browser DOM (document.createElement,
6
+ // document.body, navigator.userAgent, DOM event listeners). On Node.js /
7
+ // HarmonyOS no browser DOM exists, so we bootstrap a real DOM implementation
8
+ // (jsdom) into globalThis when `document` is missing. This is a genuine
9
+ // runtime adaptation — the AccessibilityManager still creates and manipulates
10
+ // real DOM elements — not a test-only mock.
11
+ //
12
+ // Globals are installed with Object.defineProperty because some of them
13
+ // (e.g. navigator in newer Node.js) are getter-only properties and plain
14
+ // assignment would throw in strict mode.
15
+ // ---------------------------------------------------------------------------
16
+ if (typeof globalThis.document === "undefined") {
17
+ try {
18
+ const { JSDOM } = require("jsdom");
19
+ const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>", {
20
+ url: "http://localhost/",
21
+ pretendToBeVisual: true,
22
+ userAgent: "Mozilla/5.0 (HarmonyOS; Node.js) AppleWebKit/537.36 jsdom"
23
+ });
24
+ const setGlobal = (name, value) => {
25
+ try {
26
+ Object.defineProperty(globalThis, name, {
27
+ value,
28
+ writable: true,
29
+ configurable: true,
30
+ enumerable: true
31
+ });
32
+ } catch (_e) {
33
+ // keep the existing global if it cannot be replaced
34
+ }
35
+ };
36
+ setGlobal("window", dom.window);
37
+ setGlobal("document", dom.window.document);
38
+ setGlobal("navigator", dom.window.navigator);
39
+ setGlobal("addEventListener", dom.window.addEventListener.bind(dom.window));
40
+ setGlobal("removeEventListener", dom.window.removeEventListener.bind(dom.window));
41
+ } catch (_e) {
42
+ // jsdom is not installed: preserve browser-only behaviour
43
+ // (document stays undefined, exactly as in the original package).
44
+ }
45
+ }
46
+ var AccessibilityManager = require("./AccessibilityManager.js"), accessibleTarget = require("./accessibleTarget.js");
47
+ exports.AccessibilityManager = AccessibilityManager.AccessibilityManager;
48
+ exports.accessibleTarget = accessibleTarget.accessibleTarget;
49
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
package/lib/index.mjs ADDED
@@ -0,0 +1,53 @@
1
+ // ---------------------------------------------------------------------------
2
+ // HarmonyOS / Node.js runtime adaptation
3
+ //
4
+ // AccessibilityManager operates on a real browser DOM (document.createElement,
5
+ // document.body, navigator.userAgent, DOM event listeners). On Node.js /
6
+ // HarmonyOS no browser DOM exists, so we bootstrap a real DOM implementation
7
+ // (jsdom) into globalThis when `document` is missing. This is a genuine
8
+ // runtime adaptation — the AccessibilityManager still creates and manipulates
9
+ // real DOM elements — not a test-only mock.
10
+ //
11
+ // Globals are installed with Object.defineProperty because some of them
12
+ // (e.g. navigator in newer Node.js) are getter-only properties and plain
13
+ // assignment would throw (ESM runs in strict mode).
14
+ // ---------------------------------------------------------------------------
15
+ import { createRequire } from "module";
16
+ if (typeof globalThis.document === "undefined") {
17
+ try {
18
+ const require = createRequire(import.meta.url);
19
+ const { JSDOM } = require("jsdom");
20
+ const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>", {
21
+ url: "http://localhost/",
22
+ pretendToBeVisual: true,
23
+ userAgent: "Mozilla/5.0 (HarmonyOS; Node.js) AppleWebKit/537.36 jsdom"
24
+ });
25
+ const setGlobal = (name, value) => {
26
+ try {
27
+ Object.defineProperty(globalThis, name, {
28
+ value,
29
+ writable: true,
30
+ configurable: true,
31
+ enumerable: true
32
+ });
33
+ } catch (_e) {
34
+ // keep the existing global if it cannot be replaced
35
+ }
36
+ };
37
+ setGlobal("window", dom.window);
38
+ setGlobal("document", dom.window.document);
39
+ setGlobal("navigator", dom.window.navigator);
40
+ setGlobal("addEventListener", dom.window.addEventListener.bind(dom.window));
41
+ setGlobal("removeEventListener", dom.window.removeEventListener.bind(dom.window));
42
+ } catch (_e) {
43
+ // jsdom is not installed: preserve browser-only behaviour
44
+ // (document stays undefined, exactly as in the original package).
45
+ }
46
+ }
47
+ import { AccessibilityManager } from "./AccessibilityManager.mjs";
48
+ import { accessibleTarget } from "./accessibleTarget.mjs";
49
+ export {
50
+ AccessibilityManager,
51
+ accessibleTarget
52
+ };
53
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@ohos-ports/pixi-accessibility",
3
+ "version": "7.4.3-beta.1",
4
+ "main": "lib/index.js",
5
+ "module": "lib/index.mjs",
6
+ "types": "lib/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "import": {
10
+ "types": "./lib/index.d.ts",
11
+ "default": "./lib/index.mjs"
12
+ },
13
+ "require": {
14
+ "types": "./lib/index.d.ts",
15
+ "default": "./lib/index.js"
16
+ }
17
+ }
18
+ },
19
+ "description": "Accessibility Plugin for visually impaired users (HarmonyOS port of @pixi/accessibility@7.4.3 with jsdom DOM polyfill for openharmony)",
20
+ "author": "Mat Groves",
21
+ "contributors": [
22
+ "Matt Karl <matt@mattkarl.com>"
23
+ ],
24
+ "homepage": "http://pixijs.com/",
25
+ "bugs": "https://github.com/ohos-ports/ohos-ports/issues",
26
+ "license": "MIT",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/ohos-ports/ohos-ports.git",
30
+ "directory": "ports/pixi-accessibility/7.4.3"
31
+ },
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "files": [
36
+ "lib",
37
+ "*.d.ts"
38
+ ],
39
+ "peerDependencies": {
40
+ "@pixi/core": "7.4.3",
41
+ "@pixi/display": "7.4.3",
42
+ "@pixi/events": "7.4.3"
43
+ },
44
+ "dependencies": {
45
+ "jsdom": "^30.0.1"
46
+ },
47
+ "keywords": [
48
+ "openharmony",
49
+ "harmonyos",
50
+ "ohos-ports",
51
+ "pixi",
52
+ "accessibility"
53
+ ]
54
+ }