mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Align character position in a11y tree with the actual rendering
This helps screen readers to draw selection outline at the correct position.
This commit is contained in:
@@ -157,10 +157,16 @@
|
||||
}
|
||||
|
||||
.xterm .xterm-accessibility-tree {
|
||||
font-family: monospace;
|
||||
user-select: text;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.xterm .xterm-accessibility-tree > div {
|
||||
transform-origin: left;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.xterm .live-region {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
|
||||
@@ -76,7 +76,6 @@ export class AccessibilityManager extends Disposable {
|
||||
this._rowElements[0].addEventListener('focus', this._topBoundaryFocusListener);
|
||||
this._rowElements[this._rowElements.length - 1].addEventListener('focus', this._bottomBoundaryFocusListener);
|
||||
|
||||
this._refreshRowsDimensions();
|
||||
this._accessibilityContainer.appendChild(this._rowContainer);
|
||||
|
||||
this._liveRegion = doc.createElement('div');
|
||||
@@ -119,6 +118,7 @@ export class AccessibilityManager extends Disposable {
|
||||
this.register(addDisposableDomListener(doc, 'selectionchange', () => this._handleSelectionChange()));
|
||||
this.register(this._coreBrowserService.onDprChange(() => this._refreshRowsDimensions()));
|
||||
|
||||
this._refreshRowsDimensions();
|
||||
this._refreshRows();
|
||||
this.register(toDisposable(() => {
|
||||
if (DEBUG) {
|
||||
@@ -193,6 +193,7 @@ export class AccessibilityManager extends Disposable {
|
||||
}
|
||||
element.setAttribute('aria-posinset', posInSet);
|
||||
element.setAttribute('aria-setsize', setSize);
|
||||
this._alignRowWidth(element);
|
||||
}
|
||||
}
|
||||
this._announceCharacters();
|
||||
@@ -390,19 +391,45 @@ export class AccessibilityManager extends Disposable {
|
||||
this._refreshRowDimensions(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
private _refreshRowsDimensions(): void {
|
||||
if (!this._renderService.dimensions.css.cell.height) {
|
||||
return;
|
||||
}
|
||||
this._accessibilityContainer.style.width = `${this._renderService.dimensions.css.canvas.width}px`;
|
||||
Object.assign(this._accessibilityContainer.style, {
|
||||
width: `${this._renderService.dimensions.css.canvas.width}px`,
|
||||
fontSize: `${this._terminal.options.fontSize}px`,
|
||||
});
|
||||
if (this._rowElements.length !== this._terminal.rows) {
|
||||
this._handleResize(this._terminal.rows);
|
||||
}
|
||||
for (let i = 0; i < this._terminal.rows; i++) {
|
||||
this._refreshRowDimensions(this._rowElements[i]);
|
||||
this._alignRowWidth(this._rowElements[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private _refreshRowDimensions(element: HTMLElement): void {
|
||||
element.style.height = `${this._renderService.dimensions.css.cell.height}px`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale the width of a row so that each of the character is (mostly) aligned
|
||||
* with the actual rendering. This will allow the screen reader to draw
|
||||
* selection outline at the correct position.
|
||||
*
|
||||
* On top of using the "monospace" font and correct font size, the scaling
|
||||
* here is necessary to handle characters that are not covered by the font
|
||||
* (e.g. CJK).
|
||||
*/
|
||||
private _alignRowWidth(element: HTMLElement): void {
|
||||
element.style.transform = '';
|
||||
const width = element.getBoundingClientRect().width;
|
||||
const lastColumn = this._rowColumns.get(element)?.slice(-1)?.[0];
|
||||
if (!lastColumn) {
|
||||
return;
|
||||
}
|
||||
const targetWidth = lastColumn * this._renderService.dimensions.css.cell.width;
|
||||
element.style.transform = `scaleX(${targetWidth / width})`;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user