@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 +21 -0
- package/README.md +13 -0
- package/global.d.ts +8 -0
- package/lib/AccessibilityManager.d.ts +147 -0
- package/lib/AccessibilityManager.js +193 -0
- package/lib/AccessibilityManager.js.map +1 -0
- package/lib/AccessibilityManager.mjs +197 -0
- package/lib/AccessibilityManager.mjs.map +1 -0
- package/lib/accessibleTarget.d.ts +32 -0
- package/lib/accessibleTarget.js +69 -0
- package/lib/accessibleTarget.js.map +1 -0
- package/lib/accessibleTarget.mjs +70 -0
- package/lib/accessibleTarget.mjs.map +1 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +49 -0
- package/lib/index.js.map +1 -0
- package/lib/index.mjs +53 -0
- package/lib/index.mjs.map +1 -0
- package/package.json +54 -0
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
package/global.d.ts
ADDED
|
@@ -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
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
|
package/lib/index.js.map
ADDED
|
@@ -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
|
+
}
|