@combos-fun/plugin-a11y 0.0.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/README.md +3 -0
- package/dist/plugin-a11y.cjs.js +481 -0
- package/dist/plugin-a11y.cjs.js.map +1 -0
- package/dist/plugin-a11y.cjs.prod.js +1 -0
- package/dist/plugin-a11y.d.ts +201 -0
- package/dist/plugin-a11y.esm.js +478 -0
- package/dist/plugin-a11y.esm.js.map +1 -0
- package/index.js +7 -0
- package/package.json +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var tslib = require('tslib');
|
|
4
|
+
var engine = require('@combos-fun/engine');
|
|
5
|
+
var pluginRenderer = require('@combos-fun/plugin-renderer');
|
|
6
|
+
var inspectorDecorator = require('@combos-fun/inspector-decorator');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 生成唯一的标识符
|
|
10
|
+
* @param len 长度
|
|
11
|
+
* @param radix 基
|
|
12
|
+
*/
|
|
13
|
+
function uuid(len) {
|
|
14
|
+
let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
|
|
15
|
+
let uuid = [];
|
|
16
|
+
let radix = chars.length;
|
|
17
|
+
for (let i = 0; i < len; i++)
|
|
18
|
+
uuid[i] = chars[0 | (Math.random() * radix)];
|
|
19
|
+
return uuid.join('');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 设置 dom 样式
|
|
23
|
+
* @param div 需要设置样式的dom元素
|
|
24
|
+
* @param style 样式属性
|
|
25
|
+
*/
|
|
26
|
+
const setStyle = (element, style) => {
|
|
27
|
+
const { width, height, position, left = 0, top = 0, zIndex, pointerEvents, background } = style;
|
|
28
|
+
element.style.width = `${width}px`;
|
|
29
|
+
element.style.height = `${height}px`;
|
|
30
|
+
element.style.position = position;
|
|
31
|
+
element.style.left = `${left}`;
|
|
32
|
+
element.style.top = `${top}`;
|
|
33
|
+
element.style.zIndex = `${zIndex}`;
|
|
34
|
+
element.style.pointerEvents = pointerEvents;
|
|
35
|
+
element.style.background = background;
|
|
36
|
+
element.style.border = 'none';
|
|
37
|
+
element.style.overflow = 'hidden';
|
|
38
|
+
};
|
|
39
|
+
const setTransform = (element, transform, ratioX, ratioY) => {
|
|
40
|
+
const { worldTransform } = transform;
|
|
41
|
+
const { a, b, c, d, tx, ty } = worldTransform;
|
|
42
|
+
const matrix = `matrix(${a}, ${b}, ${c}, ${d}, ${tx * ratioX}, ${ty * ratioY})`;
|
|
43
|
+
element.style.transform = `${matrix}`;
|
|
44
|
+
element.style.webkitTransform = `${matrix}`;
|
|
45
|
+
element.style.transformOrigin = 'left top';
|
|
46
|
+
element.style.webkitTransformOrigin = 'left top';
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
class A11y extends engine.Component {
|
|
50
|
+
static { this.componentName = 'A11y'; }
|
|
51
|
+
/**
|
|
52
|
+
* 无障碍组件构造函数
|
|
53
|
+
* @param param interactive 默认为 false,如果游戏对象可交互,传入 true
|
|
54
|
+
* @example
|
|
55
|
+
* // 为游戏对象提供朗读能力
|
|
56
|
+
* new A11y({hint: '这是一个div'})
|
|
57
|
+
* // 游戏对象有事件,传入 event 对象
|
|
58
|
+
* new A11y({hint: '点击事件对象', event: event})
|
|
59
|
+
* // 无障碍属性
|
|
60
|
+
* new A11y({hint:'按钮', role: 'button', state: {aria-hidden="true"}})
|
|
61
|
+
* // 自定义属性
|
|
62
|
+
* new A11y({hint: '自定义属性', attr: {key: '1'}})
|
|
63
|
+
*/
|
|
64
|
+
constructor(param) {
|
|
65
|
+
super();
|
|
66
|
+
Object.assign(this, param);
|
|
67
|
+
const { hint = '', event, delay = 0, attr = {}, role = '', props = {}, state = {} } = param;
|
|
68
|
+
this.hint = hint;
|
|
69
|
+
this.event = event;
|
|
70
|
+
this.delay = delay;
|
|
71
|
+
this.attr = attr;
|
|
72
|
+
this.role = role;
|
|
73
|
+
this.props = props;
|
|
74
|
+
this.state = state;
|
|
75
|
+
this.a11yId = `_${uuid(6)}`;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
tslib.__decorate([
|
|
79
|
+
inspectorDecorator.type('boolean')
|
|
80
|
+
], A11y.prototype, "interactive", void 0);
|
|
81
|
+
tslib.__decorate([
|
|
82
|
+
inspectorDecorator.type('string')
|
|
83
|
+
], A11y.prototype, "hint", void 0);
|
|
84
|
+
tslib.__decorate([
|
|
85
|
+
inspectorDecorator.type('number'),
|
|
86
|
+
inspectorDecorator.step(1)
|
|
87
|
+
], A11y.prototype, "delay", void 0);
|
|
88
|
+
tslib.__decorate([
|
|
89
|
+
inspectorDecorator.type('string')
|
|
90
|
+
], A11y.prototype, "role", void 0);
|
|
91
|
+
tslib.__decorate([
|
|
92
|
+
inspectorDecorator.type('string')
|
|
93
|
+
], A11y.prototype, "a11yId", void 0);
|
|
94
|
+
|
|
95
|
+
const POSITION = 'absolute';
|
|
96
|
+
const ZINDEX = 3;
|
|
97
|
+
exports.A11yActivate = void 0;
|
|
98
|
+
(function (A11yActivate) {
|
|
99
|
+
A11yActivate[A11yActivate["ENABLE"] = 0] = "ENABLE";
|
|
100
|
+
A11yActivate[A11yActivate["DISABLE"] = 1] = "DISABLE";
|
|
101
|
+
A11yActivate[A11yActivate["CHECK"] = 2] = "CHECK";
|
|
102
|
+
})(exports.A11yActivate || (exports.A11yActivate = {}));
|
|
103
|
+
/**
|
|
104
|
+
* 无障碍 DOM 的指针事件
|
|
105
|
+
*/
|
|
106
|
+
var PointerEvents;
|
|
107
|
+
(function (PointerEvents) {
|
|
108
|
+
PointerEvents["NONE"] = "none";
|
|
109
|
+
PointerEvents["AUTO"] = "auto";
|
|
110
|
+
})(PointerEvents || (PointerEvents = {}));
|
|
111
|
+
/**
|
|
112
|
+
* 无障碍 DOM 层的样式
|
|
113
|
+
*/
|
|
114
|
+
var MaskBackground;
|
|
115
|
+
(function (MaskBackground) {
|
|
116
|
+
MaskBackground["DEBUG"] = "rgba(255,0,0,0.5)";
|
|
117
|
+
MaskBackground["NONE"] = "transparent";
|
|
118
|
+
})(MaskBackground || (MaskBackground = {}));
|
|
119
|
+
/**
|
|
120
|
+
* 无障碍 DOM 的类型
|
|
121
|
+
*/
|
|
122
|
+
var ElementType;
|
|
123
|
+
(function (ElementType) {
|
|
124
|
+
ElementType["BUTTON"] = "button";
|
|
125
|
+
ElementType["DIV"] = "div";
|
|
126
|
+
})(ElementType || (ElementType = {}));
|
|
127
|
+
|
|
128
|
+
const notAttr = ['hint', 'event', 'delay', 'attr', 'role', 'props', 'state', 'a11yId', 'name'];
|
|
129
|
+
const getEventFunc = function (event, gameObject, e) {
|
|
130
|
+
['touchstart', 'touchend', 'tap'].forEach(name => {
|
|
131
|
+
event.emit(name, {
|
|
132
|
+
stopPropagation: () => e.stopPropagation(),
|
|
133
|
+
data: {
|
|
134
|
+
position: this.eventPosition,
|
|
135
|
+
},
|
|
136
|
+
gameObject,
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
let A11ySystem = class A11ySystem extends engine.System {
|
|
141
|
+
static { this.systemName = 'A11ySystem'; }
|
|
142
|
+
/**
|
|
143
|
+
*
|
|
144
|
+
* @param opt
|
|
145
|
+
*/
|
|
146
|
+
/**
|
|
147
|
+
* 无障碍插件初始化函数
|
|
148
|
+
* @param opt 无障碍插件选项
|
|
149
|
+
* @param opt.activate 是否开启无障碍能力,默认为自动根据系统读屏能力进行开启 AUTO | ENABLE | DISABLE
|
|
150
|
+
* @example
|
|
151
|
+
* // 开启调试,无障碍区域会显示红色透明背景
|
|
152
|
+
* new A11ySystem({debug: true})
|
|
153
|
+
* // 禁用无障碍
|
|
154
|
+
* new A11ySystem({activate: A11yActivate.DISABLE})
|
|
155
|
+
*/
|
|
156
|
+
constructor(opt) {
|
|
157
|
+
super(opt);
|
|
158
|
+
this.cache = new Map();
|
|
159
|
+
this.eventCache = new Map();
|
|
160
|
+
/**
|
|
161
|
+
*
|
|
162
|
+
* dom 的 zIndex
|
|
163
|
+
*/
|
|
164
|
+
this.zIndex = ZINDEX;
|
|
165
|
+
}
|
|
166
|
+
get ratioX() {
|
|
167
|
+
if (this._ratioX) {
|
|
168
|
+
return this._ratioX;
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
const success = this.setRatio();
|
|
172
|
+
if (success) {
|
|
173
|
+
return this._ratioX;
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
return 0;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
get ratioY() {
|
|
181
|
+
if (this._ratioY) {
|
|
182
|
+
return this._ratioY;
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
const success = this.setRatio();
|
|
186
|
+
if (success) {
|
|
187
|
+
return this._ratioY;
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
return 0;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
async init(opt = {}) {
|
|
195
|
+
const { activate = exports.A11yActivate.CHECK, delay = 100, checkA11yOpen = () => Promise.resolve(false), zIndex } = opt;
|
|
196
|
+
this.delay = delay;
|
|
197
|
+
this.zIndex = zIndex || this.zIndex;
|
|
198
|
+
switch (activate) {
|
|
199
|
+
case exports.A11yActivate.CHECK:
|
|
200
|
+
try {
|
|
201
|
+
this.activate = await checkA11yOpen();
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
this.activate = false;
|
|
205
|
+
}
|
|
206
|
+
break;
|
|
207
|
+
case exports.A11yActivate.DISABLE:
|
|
208
|
+
this.activate = false;
|
|
209
|
+
break;
|
|
210
|
+
case exports.A11yActivate.ENABLE:
|
|
211
|
+
this.activate = true;
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
this.debug = opt.debug || false;
|
|
215
|
+
if (this.debug) {
|
|
216
|
+
this.activate = true;
|
|
217
|
+
}
|
|
218
|
+
if (!this.activate)
|
|
219
|
+
return;
|
|
220
|
+
// 渲染出父容器
|
|
221
|
+
const div = document.createElement('div');
|
|
222
|
+
this.div = div;
|
|
223
|
+
// 如果存在父容器,则渲染这个 div,子元素则会相对这个 div 进行定位,否则直接相对于 body 进行定位
|
|
224
|
+
if (this.game.canvas.parentNode) {
|
|
225
|
+
this.game.canvas.parentNode.insertBefore(this.div, this.game.canvas);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
setRatio() {
|
|
229
|
+
const { width, height } = this.getCanvasBoundingClientRect();
|
|
230
|
+
const { renderWidth, renderHeight } = this.getRenderRect();
|
|
231
|
+
this._ratioX = width / renderWidth;
|
|
232
|
+
this._ratioY = height / renderHeight;
|
|
233
|
+
if (width || height) {
|
|
234
|
+
this.initDiv();
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
getRenderRect() {
|
|
242
|
+
const { params = { width: 300, height: 300 } } = this.game.getSystem(pluginRenderer.RendererSystem);
|
|
243
|
+
const { height: renderHeight, width: renderWidth } = params;
|
|
244
|
+
return { renderWidth, renderHeight };
|
|
245
|
+
}
|
|
246
|
+
getCanvasBoundingClientRect() {
|
|
247
|
+
// 渲染画布相对于视口的实际宽高以及位置,实际的像素
|
|
248
|
+
const { width, height, left, top } = this.game.canvas.getBoundingClientRect();
|
|
249
|
+
return { width, height, left, top };
|
|
250
|
+
}
|
|
251
|
+
initDiv() {
|
|
252
|
+
const { pageXOffset, pageYOffset } = window;
|
|
253
|
+
const { width, height, left, top } = this.getCanvasBoundingClientRect();
|
|
254
|
+
// 父容器位置
|
|
255
|
+
const style = {
|
|
256
|
+
width,
|
|
257
|
+
height,
|
|
258
|
+
left: `${left + pageXOffset}px`,
|
|
259
|
+
top: `${top + pageYOffset}px`,
|
|
260
|
+
position: POSITION,
|
|
261
|
+
zIndex: this.zIndex,
|
|
262
|
+
pointerEvents: PointerEvents.NONE,
|
|
263
|
+
background: MaskBackground.NONE,
|
|
264
|
+
};
|
|
265
|
+
setStyle(this.div, style);
|
|
266
|
+
// 给父容器设置捕获事件,用于监听事件坐标
|
|
267
|
+
this.div.addEventListener('click', e => {
|
|
268
|
+
const currentTarget = e.currentTarget;
|
|
269
|
+
const { left, top } = currentTarget.getBoundingClientRect();
|
|
270
|
+
const x = (e.pageX - left) / this.ratioX;
|
|
271
|
+
const y = (e.pageY - top) / this.ratioY;
|
|
272
|
+
this.eventPosition = { x, y };
|
|
273
|
+
}, true);
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* 监听插件更新
|
|
277
|
+
*/
|
|
278
|
+
async update() {
|
|
279
|
+
const changes = this.componentObserver.clear();
|
|
280
|
+
if (!this.activate) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
for (const changed of changes) {
|
|
284
|
+
switch (changed.type) {
|
|
285
|
+
case engine.OBSERVER_TYPE.ADD:
|
|
286
|
+
changed.componentName === 'Event' && this.addEvent(changed.gameObject);
|
|
287
|
+
changed.componentName === 'A11y' && this.add(changed);
|
|
288
|
+
break;
|
|
289
|
+
case engine.OBSERVER_TYPE.CHANGE:
|
|
290
|
+
changed.componentName === 'Transform' && this.transformChange(changed);
|
|
291
|
+
changed.componentName === 'A11y' && this.change(changed);
|
|
292
|
+
break;
|
|
293
|
+
case engine.OBSERVER_TYPE.REMOVE:
|
|
294
|
+
changed.componentName === 'Event' && this.removeEvent(changed);
|
|
295
|
+
changed.componentName === 'A11y' && this.remove(changed);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
change(changed) {
|
|
300
|
+
const component = changed.component;
|
|
301
|
+
if (changed.prop.prop[0] === 'hint') {
|
|
302
|
+
const dom = this.cache.get(component.a11yId);
|
|
303
|
+
dom?.setAttribute('aria-label', component.hint);
|
|
304
|
+
dom && this.setPosition(dom, changed.gameObject.transform);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
remove(changed) {
|
|
308
|
+
const component = changed.component;
|
|
309
|
+
if (!component)
|
|
310
|
+
return;
|
|
311
|
+
const { a11yId } = component;
|
|
312
|
+
const element = this.div.querySelector(`#${a11yId}`);
|
|
313
|
+
element && this.div.removeChild(element);
|
|
314
|
+
this.cache.delete(a11yId);
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* 监听组件被添加至游戏对象
|
|
318
|
+
* @param changed 改变的组件
|
|
319
|
+
*/
|
|
320
|
+
add(changed) {
|
|
321
|
+
if (!this.activate)
|
|
322
|
+
return;
|
|
323
|
+
const component = changed.component;
|
|
324
|
+
const { gameObject } = changed;
|
|
325
|
+
const { delay, a11yId: id } = component;
|
|
326
|
+
let { event } = component;
|
|
327
|
+
if (!gameObject)
|
|
328
|
+
return;
|
|
329
|
+
const { transform } = gameObject;
|
|
330
|
+
if (!transform)
|
|
331
|
+
return;
|
|
332
|
+
const element = document.createElement('div');
|
|
333
|
+
this.cache.set(id, element);
|
|
334
|
+
if (!event) {
|
|
335
|
+
event = gameObject.getComponent('Event');
|
|
336
|
+
}
|
|
337
|
+
setTimeout(() => {
|
|
338
|
+
this.setPosition(element, transform);
|
|
339
|
+
this.setA11yAttr(element, component);
|
|
340
|
+
if (event) {
|
|
341
|
+
this.addEvent(gameObject);
|
|
342
|
+
}
|
|
343
|
+
if (gameObject.scene) {
|
|
344
|
+
this.div.appendChild(element);
|
|
345
|
+
}
|
|
346
|
+
}, delay || this.delay);
|
|
347
|
+
}
|
|
348
|
+
// 监听 scene 改变
|
|
349
|
+
transformChange(changed) {
|
|
350
|
+
const component = changed.component;
|
|
351
|
+
const { gameObject } = changed;
|
|
352
|
+
const a11yComponent = gameObject.getComponent(A11y);
|
|
353
|
+
if (!a11yComponent)
|
|
354
|
+
return;
|
|
355
|
+
const { a11yId } = a11yComponent;
|
|
356
|
+
if (!component.inScene) {
|
|
357
|
+
// 监听 scene 删除游戏对象
|
|
358
|
+
const dom = this.div.querySelector(`#${a11yId}`);
|
|
359
|
+
dom && this.div.removeChild(dom);
|
|
360
|
+
// this.cache.delete(a11yId)
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
// 监听 scene add
|
|
364
|
+
// this.div.appendChild(this.cache)
|
|
365
|
+
if (this.cache.has(a11yId)) {
|
|
366
|
+
const addDom = this.cache.get(a11yId);
|
|
367
|
+
addDom && this.div.appendChild(addDom);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* 为无障碍组件设置监听事件
|
|
373
|
+
* @param element DOM 元素
|
|
374
|
+
* @param event 事件组件对象
|
|
375
|
+
* @param gameObject 游戏对象
|
|
376
|
+
*/
|
|
377
|
+
setEvent(element, event, gameObject, id) {
|
|
378
|
+
if (!event) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
const func = getEventFunc.bind(this, event, gameObject);
|
|
382
|
+
this.eventCache.set(id, func);
|
|
383
|
+
element.addEventListener('click', func);
|
|
384
|
+
}
|
|
385
|
+
addEvent(gameObject) {
|
|
386
|
+
const a11y = gameObject.getComponent(A11y);
|
|
387
|
+
if (!a11y)
|
|
388
|
+
return;
|
|
389
|
+
const event = gameObject.getComponent('Event');
|
|
390
|
+
if (!event)
|
|
391
|
+
return;
|
|
392
|
+
const element = this.cache.get(a11y.a11yId);
|
|
393
|
+
element && this.setEvent(element, event, gameObject, a11y.a11yId);
|
|
394
|
+
}
|
|
395
|
+
removeEvent(changed) {
|
|
396
|
+
const { gameObject } = changed;
|
|
397
|
+
const a11y = gameObject.getComponent(A11y);
|
|
398
|
+
if (!a11y)
|
|
399
|
+
return;
|
|
400
|
+
const event = changed.component;
|
|
401
|
+
if (!event)
|
|
402
|
+
return;
|
|
403
|
+
const { a11yId } = a11y;
|
|
404
|
+
const func = this.eventCache.get(a11yId);
|
|
405
|
+
const element = this.cache.get(a11yId);
|
|
406
|
+
element && element.removeEventListener('click', func);
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* 设置无障碍属性标签
|
|
410
|
+
* @param element DOM 元素
|
|
411
|
+
* @param hint 无障碍朗读文字
|
|
412
|
+
* @param interactive 是否可交互
|
|
413
|
+
*/
|
|
414
|
+
setA11yAttr(element, component) {
|
|
415
|
+
const { hint, props = {}, state = {}, role, a11yId: id } = component;
|
|
416
|
+
const realRole = role || 'text';
|
|
417
|
+
element.setAttribute('role', realRole);
|
|
418
|
+
element.setAttribute('aria-label', hint);
|
|
419
|
+
element.id = id;
|
|
420
|
+
// 这里兼容
|
|
421
|
+
const ariaProps = Object.keys(props);
|
|
422
|
+
for (const key of ariaProps) {
|
|
423
|
+
element.setAttribute(key, props[key]);
|
|
424
|
+
}
|
|
425
|
+
const ariaState = Object.keys(state);
|
|
426
|
+
for (const key of ariaState) {
|
|
427
|
+
element.setAttribute(key, state[key]);
|
|
428
|
+
}
|
|
429
|
+
for (const key of Object.keys(component)) {
|
|
430
|
+
if (typeof component[key] === 'string' && notAttr.indexOf(key) === -1 && key.indexOf('_') !== 1) {
|
|
431
|
+
element.setAttribute(key, component[key]);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* 将无障碍元素设置到对应的位置
|
|
437
|
+
* @param element DOM 元素
|
|
438
|
+
* @param transform 位置属性
|
|
439
|
+
*/
|
|
440
|
+
setPosition(element, transform) {
|
|
441
|
+
// 相对画布定位
|
|
442
|
+
// const { x: anchorX, y: anchorY } = transform.anchor
|
|
443
|
+
// 游戏对象的宽高
|
|
444
|
+
const { width, height } = transform.size;
|
|
445
|
+
// position
|
|
446
|
+
// const { x: positionX, y: positionY } = transform.position
|
|
447
|
+
// 设置无障碍 DOM 的样式,龙骨动画默认 2px
|
|
448
|
+
const style = {
|
|
449
|
+
width: width === 0 ? 1 : width * this.ratioX,
|
|
450
|
+
height: height === 0 ? 1 : height * this.ratioY,
|
|
451
|
+
position: POSITION,
|
|
452
|
+
zIndex: this.zIndex,
|
|
453
|
+
pointerEvents: PointerEvents.AUTO,
|
|
454
|
+
background: this.debug ? MaskBackground.DEBUG : MaskBackground.NONE,
|
|
455
|
+
};
|
|
456
|
+
const transformProps = {
|
|
457
|
+
...transform,
|
|
458
|
+
};
|
|
459
|
+
setStyle(element, style);
|
|
460
|
+
// 调整 DOM 的位置
|
|
461
|
+
setTransform(element, transformProps, this.ratioX, this.ratioY);
|
|
462
|
+
}
|
|
463
|
+
onDestroy() {
|
|
464
|
+
this.div.parentElement.removeChild(this.div);
|
|
465
|
+
this.cache = null;
|
|
466
|
+
this.eventCache = null;
|
|
467
|
+
this.div = null;
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
A11ySystem = tslib.__decorate([
|
|
471
|
+
engine.decorators.componentObserver({
|
|
472
|
+
A11y: ['hint'],
|
|
473
|
+
Transform: ['inScene'],
|
|
474
|
+
Event: [],
|
|
475
|
+
})
|
|
476
|
+
], A11ySystem);
|
|
477
|
+
var A11ySystem_default = A11ySystem;
|
|
478
|
+
|
|
479
|
+
exports.A11y = A11y;
|
|
480
|
+
exports.A11ySystem = A11ySystem_default;
|
|
481
|
+
//# sourceMappingURL=plugin-a11y.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-a11y.cjs.js","sources":["../lib/utils.ts","../lib/A11y.ts","../lib/constant.ts","../lib/A11ySystem.ts"],"sourcesContent":["import { A11yMaskStyle } from './constant';\n\n/**\n * 生成唯一的标识符\n * @param len 长度\n * @param radix 基\n */\nfunction uuid(len: number) {\n let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');\n let uuid = [];\n let radix = chars.length;\n for (let i = 0; i < len; i++) uuid[i] = chars[0 | (Math.random() * radix)];\n return uuid.join('');\n}\n\n/**\n * 设置 dom 样式\n * @param div 需要设置样式的dom元素\n * @param style 样式属性\n */\nconst setStyle = (element: HTMLElement, style: A11yMaskStyle) => {\n const { width, height, position, left = 0, top = 0, zIndex, pointerEvents, background } = style;\n element.style.width = `${width}px`;\n element.style.height = `${height}px`;\n element.style.position = position;\n element.style.left = `${left}`;\n element.style.top = `${top}`;\n element.style.zIndex = `${zIndex}`;\n element.style.pointerEvents = pointerEvents;\n element.style.background = background;\n element.style.border = 'none';\n element.style.overflow = 'hidden';\n};\n\nconst setTransform = (element: HTMLElement, transform, ratioX, ratioY) => {\n const { worldTransform } = transform;\n const { a, b, c, d, tx, ty } = worldTransform;\n const matrix = `matrix(${a}, ${b}, ${c}, ${d}, ${tx * ratioX}, ${ty * ratioY})`;\n element.style.transform = `${matrix}`;\n element.style.webkitTransform = `${matrix}`;\n element.style.transformOrigin = 'left top';\n element.style.webkitTransformOrigin = 'left top';\n};\n\nexport { setStyle, setTransform, uuid };\n","import {Component} from '@combos-fun/engine';\nimport {type, step} from '@combos-fun/inspector-decorator';\nimport {uuid} from './utils';\n\nexport interface A11yParams {\n hint: string;\n event?: Component;\n delay?: number;\n role?: string;\n props?: object;\n state?: object;\n attr?: object;\n a11yId?: string;\n [propName: string]: string | object | number;\n}\n\nexport default class A11y extends Component<A11yParams> {\n static componentName: string = 'A11y';\n\n /**\n * 是否可交互\n */\n @type('boolean') interactive: boolean;\n /**\n * 无障碍标签朗读内容\n */\n @type('string') hint: string;\n /**\n * 弃用,将根据Event组件自动添加\n * 事件对象\n */\n event: Component;\n /**\n * 延时加载时间(millisecond)\n */\n @type('number') @step(1) delay: number;\n\n /**\n * role 属性\n */\n @type('string') role: string;\n\n /**\n * 弃用,将属性写在component上\n * aria-value 属性\n * @example\n * aria-valuemin = \"0\"\n */\n props: object;\n\n /**\n * 弃用,将属性写在component上\n * aria state 属性\n * @example\n * aria-hidden = \"true\"\n */\n state: object;\n\n /**\n * 弃用,将属性写在component上\n * 传入自定义属性\n */\n attr: object;\n\n /**\n * 辅助Dom id 自动生成\n */\n @type('string') a11yId: string;\n\n /**\n * 无障碍组件构造函数\n * @param param interactive 默认为 false,如果游戏对象可交互,传入 true\n * @example\n * // 为游戏对象提供朗读能力\n * new A11y({hint: '这是一个div'})\n * // 游戏对象有事件,传入 event 对象\n * new A11y({hint: '点击事件对象', event: event})\n * // 无障碍属性\n * new A11y({hint:'按钮', role: 'button', state: {aria-hidden=\"true\"}})\n * // 自定义属性\n * new A11y({hint: '自定义属性', attr: {key: '1'}})\n */\n constructor(param: A11yParams) {\n super();\n Object.assign(this, param);\n const { hint = '', event, delay = 0, attr = {}, role = '', props = {}, state = {} } = param;\n this.hint = hint;\n this.event = event;\n this.delay = delay;\n this.attr = attr;\n this.role = role;\n this.props = props;\n this.state = state;\n this.a11yId = `_${uuid(6)}`;\n }\n}\n","export const POSITION = 'absolute';\nexport const ZINDEX = 3;\n\nexport enum A11yActivate {\n ENABLE = 0,\n DISABLE = 1,\n CHECK = 2,\n}\n\n/**\n * 无障碍 DOM 的指针事件\n */\nexport enum PointerEvents {\n NONE = 'none', // 元素不会成为鼠标事件的target,会被穿透\n AUTO = 'auto', // 默认值正常\n}\n\n/**\n * 无障碍 DOM 层的样式\n */\nexport enum MaskBackground {\n DEBUG = 'rgba(255,0,0,0.5)',\n NONE = 'transparent',\n}\n\n/**\n * 无障碍 DOM 的类型\n */\nexport enum ElementType {\n BUTTON = 'button',\n DIV = 'div',\n}\n\n/**\n * 无障碍遮罩层样式\n */\nexport interface A11yMaskStyle {\n width: number;\n height: number;\n background: string;\n position: string;\n left?: string;\n top?: string;\n zIndex: number;\n pointerEvents: PointerEvents;\n}\n\n/**\n * 点击事件位置\n */\nexport interface EventPosition {\n x: number;\n y: number;\n}\n","import { System, decorators, ComponentChanged, Transform, OBSERVER_TYPE } from '@combos-fun/engine';\nimport type { GameObject } from '@combos-fun/engine';\nimport { RendererSystem } from '@combos-fun/plugin-renderer';\nimport EE from 'eventemitter3';\n\nimport A11y from './A11y';\nimport { setStyle, setTransform } from './utils';\nimport {\n POSITION,\n ZINDEX,\n PointerEvents,\n MaskBackground,\n EventPosition,\n A11yMaskStyle,\n A11yActivate,\n} from './constant';\n\ninterface SystemParam {\n debug?: boolean;\n activate?: A11yActivate;\n delay?: number;\n zIndex?: number;\n checkA11yOpen?: () => Promise<boolean>;\n}\n\nconst notAttr = ['hint', 'event', 'delay', 'attr', 'role', 'props', 'state', 'a11yId', 'name'];\n\nconst getEventFunc = function (event: EE, gameObject: GameObject, e: MouseEvent) {\n ['touchstart', 'touchend', 'tap'].forEach(name => {\n event.emit(name, {\n stopPropagation: () => e.stopPropagation(),\n data: {\n position: this.eventPosition,\n },\n gameObject,\n });\n });\n};\n\n@decorators.componentObserver({\n A11y: ['hint'],\n Transform: ['inScene'],\n Event: [],\n})\nexport default class A11ySystem extends System {\n static systemName = 'A11ySystem';\n\n /**\n * 无障碍覆盖层\n */\n div: HTMLDivElement;\n /**\n * 是否开启调试\n */\n debug: boolean;\n /**\n * 横向的比例\n */\n _ratioX: number;\n /**\n * 纵向的比例\n */\n _ratioY: number;\n /**\n * 事件坐标\n */\n eventPosition: EventPosition;\n /**\n * 是否开启无障碍能力\n */\n activate: boolean;\n /**\n * dom 延迟放置\n */\n delay: number;\n cache: Map<string, HTMLElement> = new Map();\n eventCache: Map<string, (e: MouseEvent) => void> = new Map();\n /**\n * \n * dom 的 zIndex\n */\n zIndex: number = ZINDEX;\n /**\n *\n * @param opt\n */\n\n /**\n * 无障碍插件初始化函数\n * @param opt 无障碍插件选项\n * @param opt.activate 是否开启无障碍能力,默认为自动根据系统读屏能力进行开启 AUTO | ENABLE | DISABLE\n * @example\n * // 开启调试,无障碍区域会显示红色透明背景\n * new A11ySystem({debug: true})\n * // 禁用无障碍\n * new A11ySystem({activate: A11yActivate.DISABLE})\n */\n constructor(opt?: SystemParam) {\n super(opt);\n }\n\n get ratioX() {\n if (this._ratioX) {\n return this._ratioX;\n } else {\n const success = this.setRatio();\n if (success) {\n return this._ratioX;\n } else {\n return 0;\n }\n }\n }\n get ratioY() {\n if (this._ratioY) {\n return this._ratioY;\n } else {\n const success = this.setRatio();\n if (success) {\n return this._ratioY;\n } else {\n return 0;\n }\n }\n }\n\n async init(opt: SystemParam = {}) {\n const { activate = A11yActivate.CHECK, delay = 100, checkA11yOpen = () => Promise.resolve(false), zIndex } = opt;\n this.delay = delay;\n this.zIndex = zIndex || this.zIndex\n switch (activate) {\n case A11yActivate.CHECK:\n try {\n this.activate = await checkA11yOpen();\n } catch (error) {\n this.activate = false;\n }\n break;\n case A11yActivate.DISABLE:\n this.activate = false;\n break;\n case A11yActivate.ENABLE:\n this.activate = true;\n break;\n }\n this.debug = opt.debug || false;\n if (this.debug) {\n this.activate = true;\n }\n\n if (!this.activate) return;\n // 渲染出父容器\n const div = document.createElement('div');\n this.div = div;\n // 如果存在父容器,则渲染这个 div,子元素则会相对这个 div 进行定位,否则直接相对于 body 进行定位\n if (this.game.canvas.parentNode) {\n this.game.canvas.parentNode.insertBefore(this.div, this.game.canvas);\n }\n }\n setRatio() {\n const { width, height } = this.getCanvasBoundingClientRect();\n const { renderWidth, renderHeight } = this.getRenderRect();\n this._ratioX = width / renderWidth;\n this._ratioY = height / renderHeight;\n if (width || height) {\n this.initDiv();\n return true;\n } else {\n return false;\n }\n }\n getRenderRect() {\n const { params = { width: 300, height: 300 } } = this.game.getSystem(RendererSystem);\n const { height: renderHeight, width: renderWidth } = params;\n return { renderWidth, renderHeight };\n }\n getCanvasBoundingClientRect() {\n // 渲染画布相对于视口的实际宽高以及位置,实际的像素\n const { width, height, left, top } = this.game.canvas.getBoundingClientRect();\n return { width, height, left, top };\n }\n initDiv() {\n const { pageXOffset, pageYOffset } = window;\n\n const { width, height, left, top } = this.getCanvasBoundingClientRect();\n // 父容器位置\n const style: A11yMaskStyle = {\n width,\n height,\n left: `${left + pageXOffset}px`,\n top: `${top + pageYOffset}px`,\n position: POSITION,\n zIndex: this.zIndex,\n pointerEvents: PointerEvents.NONE,\n background: MaskBackground.NONE,\n };\n setStyle(this.div, style);\n // 给父容器设置捕获事件,用于监听事件坐标\n this.div.addEventListener(\n 'click',\n e => {\n const currentTarget = e.currentTarget as HTMLDivElement;\n const { left, top } = currentTarget.getBoundingClientRect();\n const x = (e.pageX - left) / this.ratioX;\n const y = (e.pageY - top) / this.ratioY;\n this.eventPosition = { x, y };\n },\n true,\n );\n }\n\n /**\n * 监听插件更新\n */\n async update() {\n const changes = this.componentObserver.clear();\n if (!this.activate) {\n return;\n }\n for (const changed of changes) {\n switch (changed.type) {\n case OBSERVER_TYPE.ADD:\n changed.componentName === 'Event' && this.addEvent(changed.gameObject);\n changed.componentName === 'A11y' && this.add(changed);\n break;\n case OBSERVER_TYPE.CHANGE:\n changed.componentName === 'Transform' && this.transformChange(changed);\n changed.componentName === 'A11y' && this.change(changed);\n break;\n case OBSERVER_TYPE.REMOVE:\n changed.componentName === 'Event' && this.removeEvent(changed);\n changed.componentName === 'A11y' && this.remove(changed);\n }\n }\n }\n\n change(changed: ComponentChanged) {\n const component = changed.component as A11y\n if (changed.prop.prop[0] === 'hint') {\n const dom = this.cache.get(component.a11yId)\n dom?.setAttribute('aria-label', component.hint)\n dom && this.setPosition(dom, changed.gameObject.transform)\n }\n }\n\n remove(changed: ComponentChanged) {\n const component = changed.component as A11y;\n if (!component) return;\n const { a11yId } = component;\n const element = this.div.querySelector(`#${a11yId}`);\n element && this.div.removeChild(element);\n this.cache.delete(a11yId);\n }\n\n /**\n * 监听组件被添加至游戏对象\n * @param changed 改变的组件\n */\n add(changed: ComponentChanged) {\n if (!this.activate) return;\n const component = changed.component as A11y;\n const { gameObject } = changed;\n const { delay, a11yId: id } = component;\n let { event } = component;\n if (!gameObject) return;\n const { transform } = gameObject;\n if (!transform) return;\n const element = document.createElement('div');\n this.cache.set(id, element);\n if (!event) {\n event = gameObject.getComponent('Event');\n }\n setTimeout(() => {\n this.setPosition(element, transform);\n this.setA11yAttr(element, component);\n if (event) {\n this.addEvent(gameObject);\n }\n if (gameObject.scene) {\n this.div.appendChild(element);\n }\n }, delay || this.delay);\n }\n\n // 监听 scene 改变\n transformChange(changed: ComponentChanged) {\n const component = changed.component as Transform;\n const { gameObject } = changed;\n const a11yComponent = gameObject.getComponent(A11y) as A11y;\n if (!a11yComponent) return;\n const { a11yId } = a11yComponent;\n if (!component.inScene) {\n // 监听 scene 删除游戏对象\n const dom = this.div.querySelector(`#${a11yId}`);\n dom && this.div.removeChild(dom);\n // this.cache.delete(a11yId)\n } else {\n // 监听 scene add\n // this.div.appendChild(this.cache)\n if (this.cache.has(a11yId)) {\n const addDom = this.cache.get(a11yId);\n addDom && this.div.appendChild(addDom);\n }\n }\n }\n\n /**\n * 为无障碍组件设置监听事件\n * @param element DOM 元素\n * @param event 事件组件对象\n * @param gameObject 游戏对象\n */\n setEvent(element: HTMLElement, event: EE, gameObject: GameObject, id) {\n if (!event) {\n return;\n }\n const func = getEventFunc.bind(this, event, gameObject) as (e: MouseEvent) => void;\n this.eventCache.set(id, func);\n element.addEventListener('click', func);\n }\n\n addEvent(gameObject: GameObject) {\n const a11y = gameObject.getComponent(A11y) as A11y;\n if (!a11y) return;\n const event = gameObject.getComponent('Event');\n if (!event) return;\n const element = this.cache.get(a11y.a11yId);\n element && this.setEvent(element, event, gameObject, a11y.a11yId);\n }\n\n removeEvent(changed: ComponentChanged) {\n const { gameObject } = changed;\n const a11y = gameObject.getComponent(A11y) as A11y;\n if (!a11y) return;\n const event = changed.component;\n if (!event) return;\n const { a11yId } = a11y;\n const func = this.eventCache.get(a11yId);\n const element = this.cache.get(a11yId);\n element && element.removeEventListener('click', func);\n }\n\n /**\n * 设置无障碍属性标签\n * @param element DOM 元素\n * @param hint 无障碍朗读文字\n * @param interactive 是否可交互\n */\n setA11yAttr(element: HTMLElement, component: A11y) {\n const { hint, props = {}, state = {}, role, a11yId: id } = component;\n const realRole = role || 'text';\n element.setAttribute('role', realRole);\n element.setAttribute('aria-label', hint);\n element.id = id;\n\n // 这里兼容\n const ariaProps = Object.keys(props);\n for (const key of ariaProps) {\n element.setAttribute(key, props[key]);\n }\n const ariaState = Object.keys(state);\n for (const key of ariaState) {\n element.setAttribute(key, state[key]);\n }\n\n for (const key of Object.keys(component)) {\n if (typeof component[key] === 'string' && notAttr.indexOf(key) === -1 && key.indexOf('_') !== 1) {\n element.setAttribute(key, component[key]);\n }\n }\n }\n\n /**\n * 将无障碍元素设置到对应的位置\n * @param element DOM 元素\n * @param transform 位置属性\n */\n setPosition(element: HTMLElement, transform: Transform) {\n // 相对画布定位\n // const { x: anchorX, y: anchorY } = transform.anchor\n // 游戏对象的宽高\n const { width, height } = transform.size;\n // position\n // const { x: positionX, y: positionY } = transform.position\n // 设置无障碍 DOM 的样式,龙骨动画默认 2px\n const style: A11yMaskStyle = {\n width: width === 0 ? 1 : width * this.ratioX,\n height: height === 0 ? 1 : height * this.ratioY,\n position: POSITION,\n zIndex: this.zIndex,\n pointerEvents: PointerEvents.AUTO,\n background: this.debug ? MaskBackground.DEBUG : MaskBackground.NONE,\n };\n const transformProps = {\n ...transform,\n };\n setStyle(element, style);\n // 调整 DOM 的位置\n setTransform(element, transformProps, this.ratioX, this.ratioY);\n }\n onDestroy() {\n this.div.parentElement.removeChild(this.div);\n this.cache = null;\n this.eventCache = null;\n this.div = null\n }\n}\n"],"names":["Component","__decorate","type","step","A11yActivate","System","RendererSystem","OBSERVER_TYPE","decorators"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var t=require("tslib"),e=require("@combos-fun/engine"),i=require("@combos-fun/plugin-renderer"),n=require("@combos-fun/inspector-decorator");const s=(t,e)=>{const{width:i,height:n,position:s,left:o=0,top:r=0,zIndex:a,pointerEvents:c,background:h}=e;t.style.width=`${i}px`,t.style.height=`${n}px`,t.style.position=s,t.style.left=`${o}`,t.style.top=`${r}`,t.style.zIndex=`${a}`,t.style.pointerEvents=c,t.style.background=h,t.style.border="none",t.style.overflow="hidden"};class o extends e.Component{static{this.componentName="A11y"}constructor(t){super(),Object.assign(this,t);const{hint:e="",event:i,delay:n=0,attr:s={},role:o="",props:r={},state:a={}}=t;this.hint=e,this.event=i,this.delay=n,this.attr=s,this.role=o,this.props=r,this.state=a,this.a11yId=`_${function(t){let e="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split(""),i=[],n=e.length;for(let s=0;s<t;s++)i[s]=e[0|Math.random()*n];return i.join("")}(6)}`}}t.__decorate([n.type("boolean")],o.prototype,"interactive",void 0),t.__decorate([n.type("string")],o.prototype,"hint",void 0),t.__decorate([n.type("number"),n.step(1)],o.prototype,"delay",void 0),t.__decorate([n.type("string")],o.prototype,"role",void 0),t.__decorate([n.type("string")],o.prototype,"a11yId",void 0);const r="absolute";var a,c,h,d;exports.A11yActivate=void 0,(a=exports.A11yActivate||(exports.A11yActivate={}))[a.ENABLE=0]="ENABLE",a[a.DISABLE=1]="DISABLE",a[a.CHECK=2]="CHECK",function(t){t.NONE="none",t.AUTO="auto"}(c||(c={})),function(t){t.DEBUG="rgba(255,0,0,0.5)",t.NONE="transparent"}(h||(h={})),function(t){t.BUTTON="button",t.DIV="div"}(d||(d={}));const p=["hint","event","delay","attr","role","props","state","a11yId","name"],v=function(t,e,i){["touchstart","touchend","tap"].forEach(n=>{t.emit(n,{stopPropagation:()=>i.stopPropagation(),data:{position:this.eventPosition},gameObject:e})})};let l=class extends e.System{static{this.systemName="A11ySystem"}constructor(t){super(t),this.cache=new Map,this.eventCache=new Map,this.zIndex=3}get ratioX(){if(this._ratioX)return this._ratioX;return this.setRatio()?this._ratioX:0}get ratioY(){if(this._ratioY)return this._ratioY;return this.setRatio()?this._ratioY:0}async init(t={}){const{activate:e=exports.A11yActivate.CHECK,delay:i=100,checkA11yOpen:n=()=>Promise.resolve(!1),zIndex:s}=t;switch(this.delay=i,this.zIndex=s||this.zIndex,e){case exports.A11yActivate.CHECK:try{this.activate=await n()}catch(t){this.activate=!1}break;case exports.A11yActivate.DISABLE:this.activate=!1;break;case exports.A11yActivate.ENABLE:this.activate=!0}if(this.debug=t.debug||!1,this.debug&&(this.activate=!0),!this.activate)return;const o=document.createElement("div");this.div=o,this.game.canvas.parentNode&&this.game.canvas.parentNode.insertBefore(this.div,this.game.canvas)}setRatio(){const{width:t,height:e}=this.getCanvasBoundingClientRect(),{renderWidth:i,renderHeight:n}=this.getRenderRect();return this._ratioX=t/i,this._ratioY=e/n,!(!t&&!e)&&(this.initDiv(),!0)}getRenderRect(){const{params:t={width:300,height:300}}=this.game.getSystem(i.RendererSystem),{height:e,width:n}=t;return{renderWidth:n,renderHeight:e}}getCanvasBoundingClientRect(){const{width:t,height:e,left:i,top:n}=this.game.canvas.getBoundingClientRect();return{width:t,height:e,left:i,top:n}}initDiv(){const{pageXOffset:t,pageYOffset:e}=window,{width:i,height:n,left:o,top:a}=this.getCanvasBoundingClientRect(),d={width:i,height:n,left:`${o+t}px`,top:`${a+e}px`,position:r,zIndex:this.zIndex,pointerEvents:c.NONE,background:h.NONE};s(this.div,d),this.div.addEventListener("click",t=>{const e=t.currentTarget,{left:i,top:n}=e.getBoundingClientRect(),s=(t.pageX-i)/this.ratioX,o=(t.pageY-n)/this.ratioY;this.eventPosition={x:s,y:o}},!0)}async update(){const t=this.componentObserver.clear();if(this.activate)for(const i of t)switch(i.type){case e.OBSERVER_TYPE.ADD:"Event"===i.componentName&&this.addEvent(i.gameObject),"A11y"===i.componentName&&this.add(i);break;case e.OBSERVER_TYPE.CHANGE:"Transform"===i.componentName&&this.transformChange(i),"A11y"===i.componentName&&this.change(i);break;case e.OBSERVER_TYPE.REMOVE:"Event"===i.componentName&&this.removeEvent(i),"A11y"===i.componentName&&this.remove(i)}}change(t){const e=t.component;if("hint"===t.prop.prop[0]){const i=this.cache.get(e.a11yId);i?.setAttribute("aria-label",e.hint),i&&this.setPosition(i,t.gameObject.transform)}}remove(t){const e=t.component;if(!e)return;const{a11yId:i}=e,n=this.div.querySelector(`#${i}`);n&&this.div.removeChild(n),this.cache.delete(i)}add(t){if(!this.activate)return;const e=t.component,{gameObject:i}=t,{delay:n,a11yId:s}=e;let{event:o}=e;if(!i)return;const{transform:r}=i;if(!r)return;const a=document.createElement("div");this.cache.set(s,a),o||(o=i.getComponent("Event")),setTimeout(()=>{this.setPosition(a,r),this.setA11yAttr(a,e),o&&this.addEvent(i),i.scene&&this.div.appendChild(a)},n||this.delay)}transformChange(t){const e=t.component,{gameObject:i}=t,n=i.getComponent(o);if(!n)return;const{a11yId:s}=n;if(e.inScene){if(this.cache.has(s)){const t=this.cache.get(s);t&&this.div.appendChild(t)}}else{const t=this.div.querySelector(`#${s}`);t&&this.div.removeChild(t)}}setEvent(t,e,i,n){if(!e)return;const s=v.bind(this,e,i);this.eventCache.set(n,s),t.addEventListener("click",s)}addEvent(t){const e=t.getComponent(o);if(!e)return;const i=t.getComponent("Event");if(!i)return;const n=this.cache.get(e.a11yId);n&&this.setEvent(n,i,t,e.a11yId)}removeEvent(t){const{gameObject:e}=t,i=e.getComponent(o);if(!i)return;if(!t.component)return;const{a11yId:n}=i,s=this.eventCache.get(n),r=this.cache.get(n);r&&r.removeEventListener("click",s)}setA11yAttr(t,e){const{hint:i,props:n={},state:s={},role:o,a11yId:r}=e,a=o||"text";t.setAttribute("role",a),t.setAttribute("aria-label",i),t.id=r;const c=Object.keys(n);for(const e of c)t.setAttribute(e,n[e]);const h=Object.keys(s);for(const e of h)t.setAttribute(e,s[e]);for(const i of Object.keys(e))"string"==typeof e[i]&&-1===p.indexOf(i)&&1!==i.indexOf("_")&&t.setAttribute(i,e[i])}setPosition(t,e){const{width:i,height:n}=e.size,o={width:0===i?1:i*this.ratioX,height:0===n?1:n*this.ratioY,position:r,zIndex:this.zIndex,pointerEvents:c.AUTO,background:this.debug?h.DEBUG:h.NONE},a={...e};s(t,o),((t,e,i,n)=>{const{worldTransform:s}=e,{a:o,b:r,c:a,d:c,tx:h,ty:d}=s,p=`matrix(${o}, ${r}, ${a}, ${c}, ${h*i}, ${d*n})`;t.style.transform=`${p}`,t.style.webkitTransform=`${p}`,t.style.transformOrigin="left top",t.style.webkitTransformOrigin="left top"})(t,a,this.ratioX,this.ratioY)}onDestroy(){this.div.parentElement.removeChild(this.div),this.cache=null,this.eventCache=null,this.div=null}};l=t.__decorate([e.decorators.componentObserver({A11y:["hint"],Transform:["inScene"],Event:[]})],l);var m=l;exports.A11y=o,exports.A11ySystem=m;
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { Component, System, ComponentChanged, GameObject, Transform } from '@combos-fun/engine';
|
|
2
|
+
import EE from 'eventemitter3';
|
|
3
|
+
|
|
4
|
+
interface A11yParams {
|
|
5
|
+
hint: string;
|
|
6
|
+
event?: Component;
|
|
7
|
+
delay?: number;
|
|
8
|
+
role?: string;
|
|
9
|
+
props?: object;
|
|
10
|
+
state?: object;
|
|
11
|
+
attr?: object;
|
|
12
|
+
a11yId?: string;
|
|
13
|
+
[propName: string]: string | object | number;
|
|
14
|
+
}
|
|
15
|
+
declare class A11y extends Component<A11yParams> {
|
|
16
|
+
static componentName: string;
|
|
17
|
+
/**
|
|
18
|
+
* 是否可交互
|
|
19
|
+
*/
|
|
20
|
+
interactive: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* 无障碍标签朗读内容
|
|
23
|
+
*/
|
|
24
|
+
hint: string;
|
|
25
|
+
/**
|
|
26
|
+
* 弃用,将根据Event组件自动添加
|
|
27
|
+
* 事件对象
|
|
28
|
+
*/
|
|
29
|
+
event: Component;
|
|
30
|
+
/**
|
|
31
|
+
* 延时加载时间(millisecond)
|
|
32
|
+
*/
|
|
33
|
+
delay: number;
|
|
34
|
+
/**
|
|
35
|
+
* role 属性
|
|
36
|
+
*/
|
|
37
|
+
role: string;
|
|
38
|
+
/**
|
|
39
|
+
* 弃用,将属性写在component上
|
|
40
|
+
* aria-value 属性
|
|
41
|
+
* @example
|
|
42
|
+
* aria-valuemin = "0"
|
|
43
|
+
*/
|
|
44
|
+
props: object;
|
|
45
|
+
/**
|
|
46
|
+
* 弃用,将属性写在component上
|
|
47
|
+
* aria state 属性
|
|
48
|
+
* @example
|
|
49
|
+
* aria-hidden = "true"
|
|
50
|
+
*/
|
|
51
|
+
state: object;
|
|
52
|
+
/**
|
|
53
|
+
* 弃用,将属性写在component上
|
|
54
|
+
* 传入自定义属性
|
|
55
|
+
*/
|
|
56
|
+
attr: object;
|
|
57
|
+
/**
|
|
58
|
+
* 辅助Dom id 自动生成
|
|
59
|
+
*/
|
|
60
|
+
a11yId: string;
|
|
61
|
+
/**
|
|
62
|
+
* 无障碍组件构造函数
|
|
63
|
+
* @param param interactive 默认为 false,如果游戏对象可交互,传入 true
|
|
64
|
+
* @example
|
|
65
|
+
* // 为游戏对象提供朗读能力
|
|
66
|
+
* new A11y({hint: '这是一个div'})
|
|
67
|
+
* // 游戏对象有事件,传入 event 对象
|
|
68
|
+
* new A11y({hint: '点击事件对象', event: event})
|
|
69
|
+
* // 无障碍属性
|
|
70
|
+
* new A11y({hint:'按钮', role: 'button', state: {aria-hidden="true"}})
|
|
71
|
+
* // 自定义属性
|
|
72
|
+
* new A11y({hint: '自定义属性', attr: {key: '1'}})
|
|
73
|
+
*/
|
|
74
|
+
constructor(param: A11yParams);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
declare enum A11yActivate {
|
|
78
|
+
ENABLE = 0,
|
|
79
|
+
DISABLE = 1,
|
|
80
|
+
CHECK = 2
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 点击事件位置
|
|
84
|
+
*/
|
|
85
|
+
interface EventPosition {
|
|
86
|
+
x: number;
|
|
87
|
+
y: number;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
interface SystemParam {
|
|
91
|
+
debug?: boolean;
|
|
92
|
+
activate?: A11yActivate;
|
|
93
|
+
delay?: number;
|
|
94
|
+
zIndex?: number;
|
|
95
|
+
checkA11yOpen?: () => Promise<boolean>;
|
|
96
|
+
}
|
|
97
|
+
declare class A11ySystem extends System {
|
|
98
|
+
static systemName: string;
|
|
99
|
+
/**
|
|
100
|
+
* 无障碍覆盖层
|
|
101
|
+
*/
|
|
102
|
+
div: HTMLDivElement;
|
|
103
|
+
/**
|
|
104
|
+
* 是否开启调试
|
|
105
|
+
*/
|
|
106
|
+
debug: boolean;
|
|
107
|
+
/**
|
|
108
|
+
* 横向的比例
|
|
109
|
+
*/
|
|
110
|
+
_ratioX: number;
|
|
111
|
+
/**
|
|
112
|
+
* 纵向的比例
|
|
113
|
+
*/
|
|
114
|
+
_ratioY: number;
|
|
115
|
+
/**
|
|
116
|
+
* 事件坐标
|
|
117
|
+
*/
|
|
118
|
+
eventPosition: EventPosition;
|
|
119
|
+
/**
|
|
120
|
+
* 是否开启无障碍能力
|
|
121
|
+
*/
|
|
122
|
+
activate: boolean;
|
|
123
|
+
/**
|
|
124
|
+
* dom 延迟放置
|
|
125
|
+
*/
|
|
126
|
+
delay: number;
|
|
127
|
+
cache: Map<string, HTMLElement>;
|
|
128
|
+
eventCache: Map<string, (e: MouseEvent) => void>;
|
|
129
|
+
/**
|
|
130
|
+
*
|
|
131
|
+
* dom 的 zIndex
|
|
132
|
+
*/
|
|
133
|
+
zIndex: number;
|
|
134
|
+
/**
|
|
135
|
+
*
|
|
136
|
+
* @param opt
|
|
137
|
+
*/
|
|
138
|
+
/**
|
|
139
|
+
* 无障碍插件初始化函数
|
|
140
|
+
* @param opt 无障碍插件选项
|
|
141
|
+
* @param opt.activate 是否开启无障碍能力,默认为自动根据系统读屏能力进行开启 AUTO | ENABLE | DISABLE
|
|
142
|
+
* @example
|
|
143
|
+
* // 开启调试,无障碍区域会显示红色透明背景
|
|
144
|
+
* new A11ySystem({debug: true})
|
|
145
|
+
* // 禁用无障碍
|
|
146
|
+
* new A11ySystem({activate: A11yActivate.DISABLE})
|
|
147
|
+
*/
|
|
148
|
+
constructor(opt?: SystemParam);
|
|
149
|
+
get ratioX(): number;
|
|
150
|
+
get ratioY(): number;
|
|
151
|
+
init(opt?: SystemParam): Promise<void>;
|
|
152
|
+
setRatio(): boolean;
|
|
153
|
+
getRenderRect(): {
|
|
154
|
+
renderWidth: number;
|
|
155
|
+
renderHeight: number;
|
|
156
|
+
};
|
|
157
|
+
getCanvasBoundingClientRect(): {
|
|
158
|
+
width: number;
|
|
159
|
+
height: number;
|
|
160
|
+
left: number;
|
|
161
|
+
top: number;
|
|
162
|
+
};
|
|
163
|
+
initDiv(): void;
|
|
164
|
+
/**
|
|
165
|
+
* 监听插件更新
|
|
166
|
+
*/
|
|
167
|
+
update(): Promise<void>;
|
|
168
|
+
change(changed: ComponentChanged): void;
|
|
169
|
+
remove(changed: ComponentChanged): void;
|
|
170
|
+
/**
|
|
171
|
+
* 监听组件被添加至游戏对象
|
|
172
|
+
* @param changed 改变的组件
|
|
173
|
+
*/
|
|
174
|
+
add(changed: ComponentChanged): void;
|
|
175
|
+
transformChange(changed: ComponentChanged): void;
|
|
176
|
+
/**
|
|
177
|
+
* 为无障碍组件设置监听事件
|
|
178
|
+
* @param element DOM 元素
|
|
179
|
+
* @param event 事件组件对象
|
|
180
|
+
* @param gameObject 游戏对象
|
|
181
|
+
*/
|
|
182
|
+
setEvent(element: HTMLElement, event: EE, gameObject: GameObject, id: any): void;
|
|
183
|
+
addEvent(gameObject: GameObject): void;
|
|
184
|
+
removeEvent(changed: ComponentChanged): void;
|
|
185
|
+
/**
|
|
186
|
+
* 设置无障碍属性标签
|
|
187
|
+
* @param element DOM 元素
|
|
188
|
+
* @param hint 无障碍朗读文字
|
|
189
|
+
* @param interactive 是否可交互
|
|
190
|
+
*/
|
|
191
|
+
setA11yAttr(element: HTMLElement, component: A11y): void;
|
|
192
|
+
/**
|
|
193
|
+
* 将无障碍元素设置到对应的位置
|
|
194
|
+
* @param element DOM 元素
|
|
195
|
+
* @param transform 位置属性
|
|
196
|
+
*/
|
|
197
|
+
setPosition(element: HTMLElement, transform: Transform): void;
|
|
198
|
+
onDestroy(): void;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export { A11y, A11yActivate, A11ySystem };
|
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
import { __decorate } from 'tslib';
|
|
2
|
+
import { Component, System, OBSERVER_TYPE, decorators } from '@combos-fun/engine';
|
|
3
|
+
import { RendererSystem } from '@combos-fun/plugin-renderer';
|
|
4
|
+
import { type, step } from '@combos-fun/inspector-decorator';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 生成唯一的标识符
|
|
8
|
+
* @param len 长度
|
|
9
|
+
* @param radix 基
|
|
10
|
+
*/
|
|
11
|
+
function uuid(len) {
|
|
12
|
+
let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
|
|
13
|
+
let uuid = [];
|
|
14
|
+
let radix = chars.length;
|
|
15
|
+
for (let i = 0; i < len; i++)
|
|
16
|
+
uuid[i] = chars[0 | (Math.random() * radix)];
|
|
17
|
+
return uuid.join('');
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 设置 dom 样式
|
|
21
|
+
* @param div 需要设置样式的dom元素
|
|
22
|
+
* @param style 样式属性
|
|
23
|
+
*/
|
|
24
|
+
const setStyle = (element, style) => {
|
|
25
|
+
const { width, height, position, left = 0, top = 0, zIndex, pointerEvents, background } = style;
|
|
26
|
+
element.style.width = `${width}px`;
|
|
27
|
+
element.style.height = `${height}px`;
|
|
28
|
+
element.style.position = position;
|
|
29
|
+
element.style.left = `${left}`;
|
|
30
|
+
element.style.top = `${top}`;
|
|
31
|
+
element.style.zIndex = `${zIndex}`;
|
|
32
|
+
element.style.pointerEvents = pointerEvents;
|
|
33
|
+
element.style.background = background;
|
|
34
|
+
element.style.border = 'none';
|
|
35
|
+
element.style.overflow = 'hidden';
|
|
36
|
+
};
|
|
37
|
+
const setTransform = (element, transform, ratioX, ratioY) => {
|
|
38
|
+
const { worldTransform } = transform;
|
|
39
|
+
const { a, b, c, d, tx, ty } = worldTransform;
|
|
40
|
+
const matrix = `matrix(${a}, ${b}, ${c}, ${d}, ${tx * ratioX}, ${ty * ratioY})`;
|
|
41
|
+
element.style.transform = `${matrix}`;
|
|
42
|
+
element.style.webkitTransform = `${matrix}`;
|
|
43
|
+
element.style.transformOrigin = 'left top';
|
|
44
|
+
element.style.webkitTransformOrigin = 'left top';
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
class A11y extends Component {
|
|
48
|
+
static { this.componentName = 'A11y'; }
|
|
49
|
+
/**
|
|
50
|
+
* 无障碍组件构造函数
|
|
51
|
+
* @param param interactive 默认为 false,如果游戏对象可交互,传入 true
|
|
52
|
+
* @example
|
|
53
|
+
* // 为游戏对象提供朗读能力
|
|
54
|
+
* new A11y({hint: '这是一个div'})
|
|
55
|
+
* // 游戏对象有事件,传入 event 对象
|
|
56
|
+
* new A11y({hint: '点击事件对象', event: event})
|
|
57
|
+
* // 无障碍属性
|
|
58
|
+
* new A11y({hint:'按钮', role: 'button', state: {aria-hidden="true"}})
|
|
59
|
+
* // 自定义属性
|
|
60
|
+
* new A11y({hint: '自定义属性', attr: {key: '1'}})
|
|
61
|
+
*/
|
|
62
|
+
constructor(param) {
|
|
63
|
+
super();
|
|
64
|
+
Object.assign(this, param);
|
|
65
|
+
const { hint = '', event, delay = 0, attr = {}, role = '', props = {}, state = {} } = param;
|
|
66
|
+
this.hint = hint;
|
|
67
|
+
this.event = event;
|
|
68
|
+
this.delay = delay;
|
|
69
|
+
this.attr = attr;
|
|
70
|
+
this.role = role;
|
|
71
|
+
this.props = props;
|
|
72
|
+
this.state = state;
|
|
73
|
+
this.a11yId = `_${uuid(6)}`;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
__decorate([
|
|
77
|
+
type('boolean')
|
|
78
|
+
], A11y.prototype, "interactive", void 0);
|
|
79
|
+
__decorate([
|
|
80
|
+
type('string')
|
|
81
|
+
], A11y.prototype, "hint", void 0);
|
|
82
|
+
__decorate([
|
|
83
|
+
type('number'),
|
|
84
|
+
step(1)
|
|
85
|
+
], A11y.prototype, "delay", void 0);
|
|
86
|
+
__decorate([
|
|
87
|
+
type('string')
|
|
88
|
+
], A11y.prototype, "role", void 0);
|
|
89
|
+
__decorate([
|
|
90
|
+
type('string')
|
|
91
|
+
], A11y.prototype, "a11yId", void 0);
|
|
92
|
+
|
|
93
|
+
const POSITION = 'absolute';
|
|
94
|
+
const ZINDEX = 3;
|
|
95
|
+
var A11yActivate;
|
|
96
|
+
(function (A11yActivate) {
|
|
97
|
+
A11yActivate[A11yActivate["ENABLE"] = 0] = "ENABLE";
|
|
98
|
+
A11yActivate[A11yActivate["DISABLE"] = 1] = "DISABLE";
|
|
99
|
+
A11yActivate[A11yActivate["CHECK"] = 2] = "CHECK";
|
|
100
|
+
})(A11yActivate || (A11yActivate = {}));
|
|
101
|
+
/**
|
|
102
|
+
* 无障碍 DOM 的指针事件
|
|
103
|
+
*/
|
|
104
|
+
var PointerEvents;
|
|
105
|
+
(function (PointerEvents) {
|
|
106
|
+
PointerEvents["NONE"] = "none";
|
|
107
|
+
PointerEvents["AUTO"] = "auto";
|
|
108
|
+
})(PointerEvents || (PointerEvents = {}));
|
|
109
|
+
/**
|
|
110
|
+
* 无障碍 DOM 层的样式
|
|
111
|
+
*/
|
|
112
|
+
var MaskBackground;
|
|
113
|
+
(function (MaskBackground) {
|
|
114
|
+
MaskBackground["DEBUG"] = "rgba(255,0,0,0.5)";
|
|
115
|
+
MaskBackground["NONE"] = "transparent";
|
|
116
|
+
})(MaskBackground || (MaskBackground = {}));
|
|
117
|
+
/**
|
|
118
|
+
* 无障碍 DOM 的类型
|
|
119
|
+
*/
|
|
120
|
+
var ElementType;
|
|
121
|
+
(function (ElementType) {
|
|
122
|
+
ElementType["BUTTON"] = "button";
|
|
123
|
+
ElementType["DIV"] = "div";
|
|
124
|
+
})(ElementType || (ElementType = {}));
|
|
125
|
+
|
|
126
|
+
const notAttr = ['hint', 'event', 'delay', 'attr', 'role', 'props', 'state', 'a11yId', 'name'];
|
|
127
|
+
const getEventFunc = function (event, gameObject, e) {
|
|
128
|
+
['touchstart', 'touchend', 'tap'].forEach(name => {
|
|
129
|
+
event.emit(name, {
|
|
130
|
+
stopPropagation: () => e.stopPropagation(),
|
|
131
|
+
data: {
|
|
132
|
+
position: this.eventPosition,
|
|
133
|
+
},
|
|
134
|
+
gameObject,
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
let A11ySystem = class A11ySystem extends System {
|
|
139
|
+
static { this.systemName = 'A11ySystem'; }
|
|
140
|
+
/**
|
|
141
|
+
*
|
|
142
|
+
* @param opt
|
|
143
|
+
*/
|
|
144
|
+
/**
|
|
145
|
+
* 无障碍插件初始化函数
|
|
146
|
+
* @param opt 无障碍插件选项
|
|
147
|
+
* @param opt.activate 是否开启无障碍能力,默认为自动根据系统读屏能力进行开启 AUTO | ENABLE | DISABLE
|
|
148
|
+
* @example
|
|
149
|
+
* // 开启调试,无障碍区域会显示红色透明背景
|
|
150
|
+
* new A11ySystem({debug: true})
|
|
151
|
+
* // 禁用无障碍
|
|
152
|
+
* new A11ySystem({activate: A11yActivate.DISABLE})
|
|
153
|
+
*/
|
|
154
|
+
constructor(opt) {
|
|
155
|
+
super(opt);
|
|
156
|
+
this.cache = new Map();
|
|
157
|
+
this.eventCache = new Map();
|
|
158
|
+
/**
|
|
159
|
+
*
|
|
160
|
+
* dom 的 zIndex
|
|
161
|
+
*/
|
|
162
|
+
this.zIndex = ZINDEX;
|
|
163
|
+
}
|
|
164
|
+
get ratioX() {
|
|
165
|
+
if (this._ratioX) {
|
|
166
|
+
return this._ratioX;
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
const success = this.setRatio();
|
|
170
|
+
if (success) {
|
|
171
|
+
return this._ratioX;
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
return 0;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
get ratioY() {
|
|
179
|
+
if (this._ratioY) {
|
|
180
|
+
return this._ratioY;
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
const success = this.setRatio();
|
|
184
|
+
if (success) {
|
|
185
|
+
return this._ratioY;
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
return 0;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
async init(opt = {}) {
|
|
193
|
+
const { activate = A11yActivate.CHECK, delay = 100, checkA11yOpen = () => Promise.resolve(false), zIndex } = opt;
|
|
194
|
+
this.delay = delay;
|
|
195
|
+
this.zIndex = zIndex || this.zIndex;
|
|
196
|
+
switch (activate) {
|
|
197
|
+
case A11yActivate.CHECK:
|
|
198
|
+
try {
|
|
199
|
+
this.activate = await checkA11yOpen();
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
this.activate = false;
|
|
203
|
+
}
|
|
204
|
+
break;
|
|
205
|
+
case A11yActivate.DISABLE:
|
|
206
|
+
this.activate = false;
|
|
207
|
+
break;
|
|
208
|
+
case A11yActivate.ENABLE:
|
|
209
|
+
this.activate = true;
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
this.debug = opt.debug || false;
|
|
213
|
+
if (this.debug) {
|
|
214
|
+
this.activate = true;
|
|
215
|
+
}
|
|
216
|
+
if (!this.activate)
|
|
217
|
+
return;
|
|
218
|
+
// 渲染出父容器
|
|
219
|
+
const div = document.createElement('div');
|
|
220
|
+
this.div = div;
|
|
221
|
+
// 如果存在父容器,则渲染这个 div,子元素则会相对这个 div 进行定位,否则直接相对于 body 进行定位
|
|
222
|
+
if (this.game.canvas.parentNode) {
|
|
223
|
+
this.game.canvas.parentNode.insertBefore(this.div, this.game.canvas);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
setRatio() {
|
|
227
|
+
const { width, height } = this.getCanvasBoundingClientRect();
|
|
228
|
+
const { renderWidth, renderHeight } = this.getRenderRect();
|
|
229
|
+
this._ratioX = width / renderWidth;
|
|
230
|
+
this._ratioY = height / renderHeight;
|
|
231
|
+
if (width || height) {
|
|
232
|
+
this.initDiv();
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
getRenderRect() {
|
|
240
|
+
const { params = { width: 300, height: 300 } } = this.game.getSystem(RendererSystem);
|
|
241
|
+
const { height: renderHeight, width: renderWidth } = params;
|
|
242
|
+
return { renderWidth, renderHeight };
|
|
243
|
+
}
|
|
244
|
+
getCanvasBoundingClientRect() {
|
|
245
|
+
// 渲染画布相对于视口的实际宽高以及位置,实际的像素
|
|
246
|
+
const { width, height, left, top } = this.game.canvas.getBoundingClientRect();
|
|
247
|
+
return { width, height, left, top };
|
|
248
|
+
}
|
|
249
|
+
initDiv() {
|
|
250
|
+
const { pageXOffset, pageYOffset } = window;
|
|
251
|
+
const { width, height, left, top } = this.getCanvasBoundingClientRect();
|
|
252
|
+
// 父容器位置
|
|
253
|
+
const style = {
|
|
254
|
+
width,
|
|
255
|
+
height,
|
|
256
|
+
left: `${left + pageXOffset}px`,
|
|
257
|
+
top: `${top + pageYOffset}px`,
|
|
258
|
+
position: POSITION,
|
|
259
|
+
zIndex: this.zIndex,
|
|
260
|
+
pointerEvents: PointerEvents.NONE,
|
|
261
|
+
background: MaskBackground.NONE,
|
|
262
|
+
};
|
|
263
|
+
setStyle(this.div, style);
|
|
264
|
+
// 给父容器设置捕获事件,用于监听事件坐标
|
|
265
|
+
this.div.addEventListener('click', e => {
|
|
266
|
+
const currentTarget = e.currentTarget;
|
|
267
|
+
const { left, top } = currentTarget.getBoundingClientRect();
|
|
268
|
+
const x = (e.pageX - left) / this.ratioX;
|
|
269
|
+
const y = (e.pageY - top) / this.ratioY;
|
|
270
|
+
this.eventPosition = { x, y };
|
|
271
|
+
}, true);
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* 监听插件更新
|
|
275
|
+
*/
|
|
276
|
+
async update() {
|
|
277
|
+
const changes = this.componentObserver.clear();
|
|
278
|
+
if (!this.activate) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
for (const changed of changes) {
|
|
282
|
+
switch (changed.type) {
|
|
283
|
+
case OBSERVER_TYPE.ADD:
|
|
284
|
+
changed.componentName === 'Event' && this.addEvent(changed.gameObject);
|
|
285
|
+
changed.componentName === 'A11y' && this.add(changed);
|
|
286
|
+
break;
|
|
287
|
+
case OBSERVER_TYPE.CHANGE:
|
|
288
|
+
changed.componentName === 'Transform' && this.transformChange(changed);
|
|
289
|
+
changed.componentName === 'A11y' && this.change(changed);
|
|
290
|
+
break;
|
|
291
|
+
case OBSERVER_TYPE.REMOVE:
|
|
292
|
+
changed.componentName === 'Event' && this.removeEvent(changed);
|
|
293
|
+
changed.componentName === 'A11y' && this.remove(changed);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
change(changed) {
|
|
298
|
+
const component = changed.component;
|
|
299
|
+
if (changed.prop.prop[0] === 'hint') {
|
|
300
|
+
const dom = this.cache.get(component.a11yId);
|
|
301
|
+
dom?.setAttribute('aria-label', component.hint);
|
|
302
|
+
dom && this.setPosition(dom, changed.gameObject.transform);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
remove(changed) {
|
|
306
|
+
const component = changed.component;
|
|
307
|
+
if (!component)
|
|
308
|
+
return;
|
|
309
|
+
const { a11yId } = component;
|
|
310
|
+
const element = this.div.querySelector(`#${a11yId}`);
|
|
311
|
+
element && this.div.removeChild(element);
|
|
312
|
+
this.cache.delete(a11yId);
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* 监听组件被添加至游戏对象
|
|
316
|
+
* @param changed 改变的组件
|
|
317
|
+
*/
|
|
318
|
+
add(changed) {
|
|
319
|
+
if (!this.activate)
|
|
320
|
+
return;
|
|
321
|
+
const component = changed.component;
|
|
322
|
+
const { gameObject } = changed;
|
|
323
|
+
const { delay, a11yId: id } = component;
|
|
324
|
+
let { event } = component;
|
|
325
|
+
if (!gameObject)
|
|
326
|
+
return;
|
|
327
|
+
const { transform } = gameObject;
|
|
328
|
+
if (!transform)
|
|
329
|
+
return;
|
|
330
|
+
const element = document.createElement('div');
|
|
331
|
+
this.cache.set(id, element);
|
|
332
|
+
if (!event) {
|
|
333
|
+
event = gameObject.getComponent('Event');
|
|
334
|
+
}
|
|
335
|
+
setTimeout(() => {
|
|
336
|
+
this.setPosition(element, transform);
|
|
337
|
+
this.setA11yAttr(element, component);
|
|
338
|
+
if (event) {
|
|
339
|
+
this.addEvent(gameObject);
|
|
340
|
+
}
|
|
341
|
+
if (gameObject.scene) {
|
|
342
|
+
this.div.appendChild(element);
|
|
343
|
+
}
|
|
344
|
+
}, delay || this.delay);
|
|
345
|
+
}
|
|
346
|
+
// 监听 scene 改变
|
|
347
|
+
transformChange(changed) {
|
|
348
|
+
const component = changed.component;
|
|
349
|
+
const { gameObject } = changed;
|
|
350
|
+
const a11yComponent = gameObject.getComponent(A11y);
|
|
351
|
+
if (!a11yComponent)
|
|
352
|
+
return;
|
|
353
|
+
const { a11yId } = a11yComponent;
|
|
354
|
+
if (!component.inScene) {
|
|
355
|
+
// 监听 scene 删除游戏对象
|
|
356
|
+
const dom = this.div.querySelector(`#${a11yId}`);
|
|
357
|
+
dom && this.div.removeChild(dom);
|
|
358
|
+
// this.cache.delete(a11yId)
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
// 监听 scene add
|
|
362
|
+
// this.div.appendChild(this.cache)
|
|
363
|
+
if (this.cache.has(a11yId)) {
|
|
364
|
+
const addDom = this.cache.get(a11yId);
|
|
365
|
+
addDom && this.div.appendChild(addDom);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* 为无障碍组件设置监听事件
|
|
371
|
+
* @param element DOM 元素
|
|
372
|
+
* @param event 事件组件对象
|
|
373
|
+
* @param gameObject 游戏对象
|
|
374
|
+
*/
|
|
375
|
+
setEvent(element, event, gameObject, id) {
|
|
376
|
+
if (!event) {
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
const func = getEventFunc.bind(this, event, gameObject);
|
|
380
|
+
this.eventCache.set(id, func);
|
|
381
|
+
element.addEventListener('click', func);
|
|
382
|
+
}
|
|
383
|
+
addEvent(gameObject) {
|
|
384
|
+
const a11y = gameObject.getComponent(A11y);
|
|
385
|
+
if (!a11y)
|
|
386
|
+
return;
|
|
387
|
+
const event = gameObject.getComponent('Event');
|
|
388
|
+
if (!event)
|
|
389
|
+
return;
|
|
390
|
+
const element = this.cache.get(a11y.a11yId);
|
|
391
|
+
element && this.setEvent(element, event, gameObject, a11y.a11yId);
|
|
392
|
+
}
|
|
393
|
+
removeEvent(changed) {
|
|
394
|
+
const { gameObject } = changed;
|
|
395
|
+
const a11y = gameObject.getComponent(A11y);
|
|
396
|
+
if (!a11y)
|
|
397
|
+
return;
|
|
398
|
+
const event = changed.component;
|
|
399
|
+
if (!event)
|
|
400
|
+
return;
|
|
401
|
+
const { a11yId } = a11y;
|
|
402
|
+
const func = this.eventCache.get(a11yId);
|
|
403
|
+
const element = this.cache.get(a11yId);
|
|
404
|
+
element && element.removeEventListener('click', func);
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* 设置无障碍属性标签
|
|
408
|
+
* @param element DOM 元素
|
|
409
|
+
* @param hint 无障碍朗读文字
|
|
410
|
+
* @param interactive 是否可交互
|
|
411
|
+
*/
|
|
412
|
+
setA11yAttr(element, component) {
|
|
413
|
+
const { hint, props = {}, state = {}, role, a11yId: id } = component;
|
|
414
|
+
const realRole = role || 'text';
|
|
415
|
+
element.setAttribute('role', realRole);
|
|
416
|
+
element.setAttribute('aria-label', hint);
|
|
417
|
+
element.id = id;
|
|
418
|
+
// 这里兼容
|
|
419
|
+
const ariaProps = Object.keys(props);
|
|
420
|
+
for (const key of ariaProps) {
|
|
421
|
+
element.setAttribute(key, props[key]);
|
|
422
|
+
}
|
|
423
|
+
const ariaState = Object.keys(state);
|
|
424
|
+
for (const key of ariaState) {
|
|
425
|
+
element.setAttribute(key, state[key]);
|
|
426
|
+
}
|
|
427
|
+
for (const key of Object.keys(component)) {
|
|
428
|
+
if (typeof component[key] === 'string' && notAttr.indexOf(key) === -1 && key.indexOf('_') !== 1) {
|
|
429
|
+
element.setAttribute(key, component[key]);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* 将无障碍元素设置到对应的位置
|
|
435
|
+
* @param element DOM 元素
|
|
436
|
+
* @param transform 位置属性
|
|
437
|
+
*/
|
|
438
|
+
setPosition(element, transform) {
|
|
439
|
+
// 相对画布定位
|
|
440
|
+
// const { x: anchorX, y: anchorY } = transform.anchor
|
|
441
|
+
// 游戏对象的宽高
|
|
442
|
+
const { width, height } = transform.size;
|
|
443
|
+
// position
|
|
444
|
+
// const { x: positionX, y: positionY } = transform.position
|
|
445
|
+
// 设置无障碍 DOM 的样式,龙骨动画默认 2px
|
|
446
|
+
const style = {
|
|
447
|
+
width: width === 0 ? 1 : width * this.ratioX,
|
|
448
|
+
height: height === 0 ? 1 : height * this.ratioY,
|
|
449
|
+
position: POSITION,
|
|
450
|
+
zIndex: this.zIndex,
|
|
451
|
+
pointerEvents: PointerEvents.AUTO,
|
|
452
|
+
background: this.debug ? MaskBackground.DEBUG : MaskBackground.NONE,
|
|
453
|
+
};
|
|
454
|
+
const transformProps = {
|
|
455
|
+
...transform,
|
|
456
|
+
};
|
|
457
|
+
setStyle(element, style);
|
|
458
|
+
// 调整 DOM 的位置
|
|
459
|
+
setTransform(element, transformProps, this.ratioX, this.ratioY);
|
|
460
|
+
}
|
|
461
|
+
onDestroy() {
|
|
462
|
+
this.div.parentElement.removeChild(this.div);
|
|
463
|
+
this.cache = null;
|
|
464
|
+
this.eventCache = null;
|
|
465
|
+
this.div = null;
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
A11ySystem = __decorate([
|
|
469
|
+
decorators.componentObserver({
|
|
470
|
+
A11y: ['hint'],
|
|
471
|
+
Transform: ['inScene'],
|
|
472
|
+
Event: [],
|
|
473
|
+
})
|
|
474
|
+
], A11ySystem);
|
|
475
|
+
var A11ySystem_default = A11ySystem;
|
|
476
|
+
|
|
477
|
+
export { A11y, A11yActivate, A11ySystem_default as A11ySystem };
|
|
478
|
+
//# sourceMappingURL=plugin-a11y.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-a11y.esm.js","sources":["../lib/utils.ts","../lib/A11y.ts","../lib/constant.ts","../lib/A11ySystem.ts"],"sourcesContent":["import { A11yMaskStyle } from './constant';\n\n/**\n * 生成唯一的标识符\n * @param len 长度\n * @param radix 基\n */\nfunction uuid(len: number) {\n let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');\n let uuid = [];\n let radix = chars.length;\n for (let i = 0; i < len; i++) uuid[i] = chars[0 | (Math.random() * radix)];\n return uuid.join('');\n}\n\n/**\n * 设置 dom 样式\n * @param div 需要设置样式的dom元素\n * @param style 样式属性\n */\nconst setStyle = (element: HTMLElement, style: A11yMaskStyle) => {\n const { width, height, position, left = 0, top = 0, zIndex, pointerEvents, background } = style;\n element.style.width = `${width}px`;\n element.style.height = `${height}px`;\n element.style.position = position;\n element.style.left = `${left}`;\n element.style.top = `${top}`;\n element.style.zIndex = `${zIndex}`;\n element.style.pointerEvents = pointerEvents;\n element.style.background = background;\n element.style.border = 'none';\n element.style.overflow = 'hidden';\n};\n\nconst setTransform = (element: HTMLElement, transform, ratioX, ratioY) => {\n const { worldTransform } = transform;\n const { a, b, c, d, tx, ty } = worldTransform;\n const matrix = `matrix(${a}, ${b}, ${c}, ${d}, ${tx * ratioX}, ${ty * ratioY})`;\n element.style.transform = `${matrix}`;\n element.style.webkitTransform = `${matrix}`;\n element.style.transformOrigin = 'left top';\n element.style.webkitTransformOrigin = 'left top';\n};\n\nexport { setStyle, setTransform, uuid };\n","import {Component} from '@combos-fun/engine';\nimport {type, step} from '@combos-fun/inspector-decorator';\nimport {uuid} from './utils';\n\nexport interface A11yParams {\n hint: string;\n event?: Component;\n delay?: number;\n role?: string;\n props?: object;\n state?: object;\n attr?: object;\n a11yId?: string;\n [propName: string]: string | object | number;\n}\n\nexport default class A11y extends Component<A11yParams> {\n static componentName: string = 'A11y';\n\n /**\n * 是否可交互\n */\n @type('boolean') interactive: boolean;\n /**\n * 无障碍标签朗读内容\n */\n @type('string') hint: string;\n /**\n * 弃用,将根据Event组件自动添加\n * 事件对象\n */\n event: Component;\n /**\n * 延时加载时间(millisecond)\n */\n @type('number') @step(1) delay: number;\n\n /**\n * role 属性\n */\n @type('string') role: string;\n\n /**\n * 弃用,将属性写在component上\n * aria-value 属性\n * @example\n * aria-valuemin = \"0\"\n */\n props: object;\n\n /**\n * 弃用,将属性写在component上\n * aria state 属性\n * @example\n * aria-hidden = \"true\"\n */\n state: object;\n\n /**\n * 弃用,将属性写在component上\n * 传入自定义属性\n */\n attr: object;\n\n /**\n * 辅助Dom id 自动生成\n */\n @type('string') a11yId: string;\n\n /**\n * 无障碍组件构造函数\n * @param param interactive 默认为 false,如果游戏对象可交互,传入 true\n * @example\n * // 为游戏对象提供朗读能力\n * new A11y({hint: '这是一个div'})\n * // 游戏对象有事件,传入 event 对象\n * new A11y({hint: '点击事件对象', event: event})\n * // 无障碍属性\n * new A11y({hint:'按钮', role: 'button', state: {aria-hidden=\"true\"}})\n * // 自定义属性\n * new A11y({hint: '自定义属性', attr: {key: '1'}})\n */\n constructor(param: A11yParams) {\n super();\n Object.assign(this, param);\n const { hint = '', event, delay = 0, attr = {}, role = '', props = {}, state = {} } = param;\n this.hint = hint;\n this.event = event;\n this.delay = delay;\n this.attr = attr;\n this.role = role;\n this.props = props;\n this.state = state;\n this.a11yId = `_${uuid(6)}`;\n }\n}\n","export const POSITION = 'absolute';\nexport const ZINDEX = 3;\n\nexport enum A11yActivate {\n ENABLE = 0,\n DISABLE = 1,\n CHECK = 2,\n}\n\n/**\n * 无障碍 DOM 的指针事件\n */\nexport enum PointerEvents {\n NONE = 'none', // 元素不会成为鼠标事件的target,会被穿透\n AUTO = 'auto', // 默认值正常\n}\n\n/**\n * 无障碍 DOM 层的样式\n */\nexport enum MaskBackground {\n DEBUG = 'rgba(255,0,0,0.5)',\n NONE = 'transparent',\n}\n\n/**\n * 无障碍 DOM 的类型\n */\nexport enum ElementType {\n BUTTON = 'button',\n DIV = 'div',\n}\n\n/**\n * 无障碍遮罩层样式\n */\nexport interface A11yMaskStyle {\n width: number;\n height: number;\n background: string;\n position: string;\n left?: string;\n top?: string;\n zIndex: number;\n pointerEvents: PointerEvents;\n}\n\n/**\n * 点击事件位置\n */\nexport interface EventPosition {\n x: number;\n y: number;\n}\n","import { System, decorators, ComponentChanged, Transform, OBSERVER_TYPE } from '@combos-fun/engine';\nimport type { GameObject } from '@combos-fun/engine';\nimport { RendererSystem } from '@combos-fun/plugin-renderer';\nimport EE from 'eventemitter3';\n\nimport A11y from './A11y';\nimport { setStyle, setTransform } from './utils';\nimport {\n POSITION,\n ZINDEX,\n PointerEvents,\n MaskBackground,\n EventPosition,\n A11yMaskStyle,\n A11yActivate,\n} from './constant';\n\ninterface SystemParam {\n debug?: boolean;\n activate?: A11yActivate;\n delay?: number;\n zIndex?: number;\n checkA11yOpen?: () => Promise<boolean>;\n}\n\nconst notAttr = ['hint', 'event', 'delay', 'attr', 'role', 'props', 'state', 'a11yId', 'name'];\n\nconst getEventFunc = function (event: EE, gameObject: GameObject, e: MouseEvent) {\n ['touchstart', 'touchend', 'tap'].forEach(name => {\n event.emit(name, {\n stopPropagation: () => e.stopPropagation(),\n data: {\n position: this.eventPosition,\n },\n gameObject,\n });\n });\n};\n\n@decorators.componentObserver({\n A11y: ['hint'],\n Transform: ['inScene'],\n Event: [],\n})\nexport default class A11ySystem extends System {\n static systemName = 'A11ySystem';\n\n /**\n * 无障碍覆盖层\n */\n div: HTMLDivElement;\n /**\n * 是否开启调试\n */\n debug: boolean;\n /**\n * 横向的比例\n */\n _ratioX: number;\n /**\n * 纵向的比例\n */\n _ratioY: number;\n /**\n * 事件坐标\n */\n eventPosition: EventPosition;\n /**\n * 是否开启无障碍能力\n */\n activate: boolean;\n /**\n * dom 延迟放置\n */\n delay: number;\n cache: Map<string, HTMLElement> = new Map();\n eventCache: Map<string, (e: MouseEvent) => void> = new Map();\n /**\n * \n * dom 的 zIndex\n */\n zIndex: number = ZINDEX;\n /**\n *\n * @param opt\n */\n\n /**\n * 无障碍插件初始化函数\n * @param opt 无障碍插件选项\n * @param opt.activate 是否开启无障碍能力,默认为自动根据系统读屏能力进行开启 AUTO | ENABLE | DISABLE\n * @example\n * // 开启调试,无障碍区域会显示红色透明背景\n * new A11ySystem({debug: true})\n * // 禁用无障碍\n * new A11ySystem({activate: A11yActivate.DISABLE})\n */\n constructor(opt?: SystemParam) {\n super(opt);\n }\n\n get ratioX() {\n if (this._ratioX) {\n return this._ratioX;\n } else {\n const success = this.setRatio();\n if (success) {\n return this._ratioX;\n } else {\n return 0;\n }\n }\n }\n get ratioY() {\n if (this._ratioY) {\n return this._ratioY;\n } else {\n const success = this.setRatio();\n if (success) {\n return this._ratioY;\n } else {\n return 0;\n }\n }\n }\n\n async init(opt: SystemParam = {}) {\n const { activate = A11yActivate.CHECK, delay = 100, checkA11yOpen = () => Promise.resolve(false), zIndex } = opt;\n this.delay = delay;\n this.zIndex = zIndex || this.zIndex\n switch (activate) {\n case A11yActivate.CHECK:\n try {\n this.activate = await checkA11yOpen();\n } catch (error) {\n this.activate = false;\n }\n break;\n case A11yActivate.DISABLE:\n this.activate = false;\n break;\n case A11yActivate.ENABLE:\n this.activate = true;\n break;\n }\n this.debug = opt.debug || false;\n if (this.debug) {\n this.activate = true;\n }\n\n if (!this.activate) return;\n // 渲染出父容器\n const div = document.createElement('div');\n this.div = div;\n // 如果存在父容器,则渲染这个 div,子元素则会相对这个 div 进行定位,否则直接相对于 body 进行定位\n if (this.game.canvas.parentNode) {\n this.game.canvas.parentNode.insertBefore(this.div, this.game.canvas);\n }\n }\n setRatio() {\n const { width, height } = this.getCanvasBoundingClientRect();\n const { renderWidth, renderHeight } = this.getRenderRect();\n this._ratioX = width / renderWidth;\n this._ratioY = height / renderHeight;\n if (width || height) {\n this.initDiv();\n return true;\n } else {\n return false;\n }\n }\n getRenderRect() {\n const { params = { width: 300, height: 300 } } = this.game.getSystem(RendererSystem);\n const { height: renderHeight, width: renderWidth } = params;\n return { renderWidth, renderHeight };\n }\n getCanvasBoundingClientRect() {\n // 渲染画布相对于视口的实际宽高以及位置,实际的像素\n const { width, height, left, top } = this.game.canvas.getBoundingClientRect();\n return { width, height, left, top };\n }\n initDiv() {\n const { pageXOffset, pageYOffset } = window;\n\n const { width, height, left, top } = this.getCanvasBoundingClientRect();\n // 父容器位置\n const style: A11yMaskStyle = {\n width,\n height,\n left: `${left + pageXOffset}px`,\n top: `${top + pageYOffset}px`,\n position: POSITION,\n zIndex: this.zIndex,\n pointerEvents: PointerEvents.NONE,\n background: MaskBackground.NONE,\n };\n setStyle(this.div, style);\n // 给父容器设置捕获事件,用于监听事件坐标\n this.div.addEventListener(\n 'click',\n e => {\n const currentTarget = e.currentTarget as HTMLDivElement;\n const { left, top } = currentTarget.getBoundingClientRect();\n const x = (e.pageX - left) / this.ratioX;\n const y = (e.pageY - top) / this.ratioY;\n this.eventPosition = { x, y };\n },\n true,\n );\n }\n\n /**\n * 监听插件更新\n */\n async update() {\n const changes = this.componentObserver.clear();\n if (!this.activate) {\n return;\n }\n for (const changed of changes) {\n switch (changed.type) {\n case OBSERVER_TYPE.ADD:\n changed.componentName === 'Event' && this.addEvent(changed.gameObject);\n changed.componentName === 'A11y' && this.add(changed);\n break;\n case OBSERVER_TYPE.CHANGE:\n changed.componentName === 'Transform' && this.transformChange(changed);\n changed.componentName === 'A11y' && this.change(changed);\n break;\n case OBSERVER_TYPE.REMOVE:\n changed.componentName === 'Event' && this.removeEvent(changed);\n changed.componentName === 'A11y' && this.remove(changed);\n }\n }\n }\n\n change(changed: ComponentChanged) {\n const component = changed.component as A11y\n if (changed.prop.prop[0] === 'hint') {\n const dom = this.cache.get(component.a11yId)\n dom?.setAttribute('aria-label', component.hint)\n dom && this.setPosition(dom, changed.gameObject.transform)\n }\n }\n\n remove(changed: ComponentChanged) {\n const component = changed.component as A11y;\n if (!component) return;\n const { a11yId } = component;\n const element = this.div.querySelector(`#${a11yId}`);\n element && this.div.removeChild(element);\n this.cache.delete(a11yId);\n }\n\n /**\n * 监听组件被添加至游戏对象\n * @param changed 改变的组件\n */\n add(changed: ComponentChanged) {\n if (!this.activate) return;\n const component = changed.component as A11y;\n const { gameObject } = changed;\n const { delay, a11yId: id } = component;\n let { event } = component;\n if (!gameObject) return;\n const { transform } = gameObject;\n if (!transform) return;\n const element = document.createElement('div');\n this.cache.set(id, element);\n if (!event) {\n event = gameObject.getComponent('Event');\n }\n setTimeout(() => {\n this.setPosition(element, transform);\n this.setA11yAttr(element, component);\n if (event) {\n this.addEvent(gameObject);\n }\n if (gameObject.scene) {\n this.div.appendChild(element);\n }\n }, delay || this.delay);\n }\n\n // 监听 scene 改变\n transformChange(changed: ComponentChanged) {\n const component = changed.component as Transform;\n const { gameObject } = changed;\n const a11yComponent = gameObject.getComponent(A11y) as A11y;\n if (!a11yComponent) return;\n const { a11yId } = a11yComponent;\n if (!component.inScene) {\n // 监听 scene 删除游戏对象\n const dom = this.div.querySelector(`#${a11yId}`);\n dom && this.div.removeChild(dom);\n // this.cache.delete(a11yId)\n } else {\n // 监听 scene add\n // this.div.appendChild(this.cache)\n if (this.cache.has(a11yId)) {\n const addDom = this.cache.get(a11yId);\n addDom && this.div.appendChild(addDom);\n }\n }\n }\n\n /**\n * 为无障碍组件设置监听事件\n * @param element DOM 元素\n * @param event 事件组件对象\n * @param gameObject 游戏对象\n */\n setEvent(element: HTMLElement, event: EE, gameObject: GameObject, id) {\n if (!event) {\n return;\n }\n const func = getEventFunc.bind(this, event, gameObject) as (e: MouseEvent) => void;\n this.eventCache.set(id, func);\n element.addEventListener('click', func);\n }\n\n addEvent(gameObject: GameObject) {\n const a11y = gameObject.getComponent(A11y) as A11y;\n if (!a11y) return;\n const event = gameObject.getComponent('Event');\n if (!event) return;\n const element = this.cache.get(a11y.a11yId);\n element && this.setEvent(element, event, gameObject, a11y.a11yId);\n }\n\n removeEvent(changed: ComponentChanged) {\n const { gameObject } = changed;\n const a11y = gameObject.getComponent(A11y) as A11y;\n if (!a11y) return;\n const event = changed.component;\n if (!event) return;\n const { a11yId } = a11y;\n const func = this.eventCache.get(a11yId);\n const element = this.cache.get(a11yId);\n element && element.removeEventListener('click', func);\n }\n\n /**\n * 设置无障碍属性标签\n * @param element DOM 元素\n * @param hint 无障碍朗读文字\n * @param interactive 是否可交互\n */\n setA11yAttr(element: HTMLElement, component: A11y) {\n const { hint, props = {}, state = {}, role, a11yId: id } = component;\n const realRole = role || 'text';\n element.setAttribute('role', realRole);\n element.setAttribute('aria-label', hint);\n element.id = id;\n\n // 这里兼容\n const ariaProps = Object.keys(props);\n for (const key of ariaProps) {\n element.setAttribute(key, props[key]);\n }\n const ariaState = Object.keys(state);\n for (const key of ariaState) {\n element.setAttribute(key, state[key]);\n }\n\n for (const key of Object.keys(component)) {\n if (typeof component[key] === 'string' && notAttr.indexOf(key) === -1 && key.indexOf('_') !== 1) {\n element.setAttribute(key, component[key]);\n }\n }\n }\n\n /**\n * 将无障碍元素设置到对应的位置\n * @param element DOM 元素\n * @param transform 位置属性\n */\n setPosition(element: HTMLElement, transform: Transform) {\n // 相对画布定位\n // const { x: anchorX, y: anchorY } = transform.anchor\n // 游戏对象的宽高\n const { width, height } = transform.size;\n // position\n // const { x: positionX, y: positionY } = transform.position\n // 设置无障碍 DOM 的样式,龙骨动画默认 2px\n const style: A11yMaskStyle = {\n width: width === 0 ? 1 : width * this.ratioX,\n height: height === 0 ? 1 : height * this.ratioY,\n position: POSITION,\n zIndex: this.zIndex,\n pointerEvents: PointerEvents.AUTO,\n background: this.debug ? MaskBackground.DEBUG : MaskBackground.NONE,\n };\n const transformProps = {\n ...transform,\n };\n setStyle(element, style);\n // 调整 DOM 的位置\n setTransform(element, transformProps, this.ratioX, this.ratioY);\n }\n onDestroy() {\n this.div.parentElement.removeChild(this.div);\n this.cache = null;\n this.eventCache = null;\n this.div = null\n }\n}\n"],"names":[],"mappings":"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"}
|
package/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@combos-fun/plugin-a11y",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "@combos-fun/plugin-a11y",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"module": "dist/plugin-a11y.esm.js",
|
|
7
|
+
"bundle": "CombosFun.plugin.a11y",
|
|
8
|
+
"unpkg": "dist/CombosFun.plugin.a11y.min.js",
|
|
9
|
+
"files": [
|
|
10
|
+
"index.js",
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"types": "dist/plugin-a11y.d.ts",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"combos-fun",
|
|
16
|
+
"game"
|
|
17
|
+
],
|
|
18
|
+
"author": "sun668 <q947692259@gmail.com>",
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"eventemitter3": "^5.0.4",
|
|
21
|
+
"@combos-fun/inspector-decorator": "0.0.1",
|
|
22
|
+
"@combos-fun/plugin-renderer": "0.0.1",
|
|
23
|
+
"@combos-fun/engine": "0.0.1"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "node ../../scripts/build-package.mjs"
|
|
27
|
+
}
|
|
28
|
+
}
|