@xterm/xterm 5.6.0-beta.19 → 5.6.0-beta.20

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xterm/xterm",
3
3
  "description": "Full xterm terminal, in your browser",
4
- "version": "5.6.0-beta.19",
4
+ "version": "5.6.0-beta.20",
5
5
  "main": "lib/xterm.js",
6
6
  "style": "css/xterm.css",
7
7
  "types": "typings/xterm.d.ts",
@@ -58,10 +58,11 @@ export class AccessibilityManager extends Disposable {
58
58
  @IRenderService private readonly _renderService: IRenderService
59
59
  ) {
60
60
  super();
61
- this._accessibilityContainer = this._coreBrowserService.mainDocument.createElement('div');
61
+ const doc = this._coreBrowserService.mainDocument;
62
+ this._accessibilityContainer = doc.createElement('div');
62
63
  this._accessibilityContainer.classList.add('xterm-accessibility');
63
64
 
64
- this._rowContainer = this._coreBrowserService.mainDocument.createElement('div');
65
+ this._rowContainer = doc.createElement('div');
65
66
  this._rowContainer.setAttribute('role', 'list');
66
67
  this._rowContainer.classList.add('xterm-accessibility-tree');
67
68
  this._rowElements = [];
@@ -75,10 +76,9 @@ export class AccessibilityManager extends Disposable {
75
76
  this._rowElements[0].addEventListener('focus', this._topBoundaryFocusListener);
76
77
  this._rowElements[this._rowElements.length - 1].addEventListener('focus', this._bottomBoundaryFocusListener);
77
78
 
78
- this._refreshRowsDimensions();
79
79
  this._accessibilityContainer.appendChild(this._rowContainer);
80
80
 
81
- this._liveRegion = this._coreBrowserService.mainDocument.createElement('div');
81
+ this._liveRegion = doc.createElement('div');
82
82
  this._liveRegion.classList.add('live-region');
83
83
  this._liveRegion.setAttribute('aria-live', 'assertive');
84
84
  this._accessibilityContainer.appendChild(this._liveRegion);
@@ -93,12 +93,12 @@ export class AccessibilityManager extends Disposable {
93
93
  this._rowContainer.classList.add('debug');
94
94
 
95
95
  // Use a `<div class="xterm">` container so that the css will still apply.
96
- this._debugRootContainer = document.createElement('div');
96
+ this._debugRootContainer = doc.createElement('div');
97
97
  this._debugRootContainer.classList.add('xterm');
98
98
 
99
- this._debugRootContainer.appendChild(document.createTextNode('------start a11y------'));
99
+ this._debugRootContainer.appendChild(doc.createTextNode('------start a11y------'));
100
100
  this._debugRootContainer.appendChild(this._accessibilityContainer);
101
- this._debugRootContainer.appendChild(document.createTextNode('------end a11y------'));
101
+ this._debugRootContainer.appendChild(doc.createTextNode('------end a11y------'));
102
102
 
103
103
  this._terminal.element.insertAdjacentElement('afterend', this._debugRootContainer);
104
104
  } else {
@@ -115,9 +115,10 @@ export class AccessibilityManager extends Disposable {
115
115
  this.register(this._terminal.onKey(e => this._handleKey(e.key)));
116
116
  this.register(this._terminal.onBlur(() => this._clearLiveRegion()));
117
117
  this.register(this._renderService.onDimensionsChange(() => this._refreshRowsDimensions()));
118
- this.register(addDisposableDomListener(document, 'selectionchange', () => this._handleSelectionChange()));
118
+ this.register(addDisposableDomListener(doc, 'selectionchange', () => this._handleSelectionChange()));
119
119
  this.register(this._coreBrowserService.onDprChange(() => this._refreshRowsDimensions()));
120
120
 
121
+ this._refreshRowsDimensions();
121
122
  this._refreshRows();
122
123
  this.register(toDisposable(() => {
123
124
  if (DEBUG) {
@@ -192,6 +193,7 @@ export class AccessibilityManager extends Disposable {
192
193
  }
193
194
  element.setAttribute('aria-posinset', posInSet);
194
195
  element.setAttribute('aria-setsize', setSize);
196
+ this._alignRowWidth(element);
195
197
  }
196
198
  }
197
199
  this._announceCharacters();
@@ -270,7 +272,7 @@ export class AccessibilityManager extends Disposable {
270
272
  return;
271
273
  }
272
274
 
273
- const selection = document.getSelection();
275
+ const selection = this._coreBrowserService.mainDocument.getSelection();
274
276
  if (!selection) {
275
277
  return;
276
278
  }
@@ -389,19 +391,45 @@ export class AccessibilityManager extends Disposable {
389
391
  this._refreshRowDimensions(element);
390
392
  return element;
391
393
  }
394
+
392
395
  private _refreshRowsDimensions(): void {
393
396
  if (!this._renderService.dimensions.css.cell.height) {
394
397
  return;
395
398
  }
396
- this._accessibilityContainer.style.width = `${this._renderService.dimensions.css.canvas.width}px`;
399
+ Object.assign(this._accessibilityContainer.style, {
400
+ width: `${this._renderService.dimensions.css.canvas.width}px`,
401
+ fontSize: `${this._terminal.options.fontSize}px`
402
+ });
397
403
  if (this._rowElements.length !== this._terminal.rows) {
398
404
  this._handleResize(this._terminal.rows);
399
405
  }
400
406
  for (let i = 0; i < this._terminal.rows; i++) {
401
407
  this._refreshRowDimensions(this._rowElements[i]);
408
+ this._alignRowWidth(this._rowElements[i]);
402
409
  }
403
410
  }
411
+
404
412
  private _refreshRowDimensions(element: HTMLElement): void {
405
413
  element.style.height = `${this._renderService.dimensions.css.cell.height}px`;
406
414
  }
415
+
416
+ /**
417
+ * Scale the width of a row so that each of the character is (mostly) aligned
418
+ * with the actual rendering. This will allow the screen reader to draw
419
+ * selection outline at the correct position.
420
+ *
421
+ * On top of using the "monospace" font and correct font size, the scaling
422
+ * here is necessary to handle characters that are not covered by the font
423
+ * (e.g. CJK).
424
+ */
425
+ private _alignRowWidth(element: HTMLElement): void {
426
+ element.style.transform = '';
427
+ const width = element.getBoundingClientRect().width;
428
+ const lastColumn = this._rowColumns.get(element)?.slice(-1)?.[0];
429
+ if (!lastColumn) {
430
+ return;
431
+ }
432
+ const targetWidth = lastColumn * this._renderService.dimensions.css.cell.width;
433
+ element.style.transform = `scaleX(${targetWidth / width})`;
434
+ }
407
435
  }