mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-06-19 21:09:51 +08:00
fix(a11y): enable screen reader support for python terminal (#60154)
This commit is contained in:
parent
ed2bdfcf96
commit
46c008c112
@ -849,7 +849,8 @@
|
||||
"opens-new-window": "Opens in new window",
|
||||
"rsa-checkbox": "I have tried the Read-Search-Ask method",
|
||||
"similar-questions-checkbox": "I have searched for similar questions that have already been answered on the forum",
|
||||
"edit-my-profile": "Edit my profile"
|
||||
"edit-my-profile": "Edit my profile",
|
||||
"terminal-output": "Terminal output"
|
||||
},
|
||||
"flash": {
|
||||
"no-email-in-userinfo": "We could not retrieve an email from your chosen provider. Please try another provider or use the 'Continue with Email' option.",
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import React, { MutableRefObject, useEffect, useRef } from 'react';
|
||||
import type { IDisposable, Terminal } from 'xterm';
|
||||
import type { FitAddon } from 'xterm-addon-fit';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { registerTerminal } from '../utils/python-worker-handler';
|
||||
|
||||
@ -23,6 +24,7 @@ export const XtermTerminal = ({
|
||||
dimensions?: { height: number; width: number };
|
||||
}) => {
|
||||
const termContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
void registerServiceWorker();
|
||||
@ -43,7 +45,25 @@ export const XtermTerminal = ({
|
||||
if (termContainerRef.current) term.open(termContainerRef.current);
|
||||
fitAddon.fit();
|
||||
|
||||
const print = (text?: string) => term?.writeln(`${text ?? ''}`);
|
||||
// xterm does provide a11y support via the `screenReaderMode` option.
|
||||
// However, the mode only works best if the user interacts with the terminal directly.
|
||||
// Since we feed the content to xterm, it's better to control the output a11y ourselves.
|
||||
const termContainerDiv =
|
||||
termContainerRef.current?.querySelector('.xterm');
|
||||
const outputForScreenReader = document.createElement('div');
|
||||
|
||||
outputForScreenReader.setAttribute('role', 'region');
|
||||
outputForScreenReader.setAttribute(
|
||||
'aria-label',
|
||||
t('aria.terminal-output')
|
||||
);
|
||||
outputForScreenReader.classList.add('sr-only');
|
||||
termContainerDiv?.appendChild(outputForScreenReader);
|
||||
|
||||
const print = (text?: string) => {
|
||||
term?.writeln(`${text ?? ''}`);
|
||||
outputForScreenReader.textContent = text ?? '';
|
||||
};
|
||||
|
||||
// TODO: prevent user from moving cursor outside the current input line and
|
||||
// handle insertion and deletion properly. While backspace and delete don't
|
||||
@ -94,6 +114,8 @@ export const XtermTerminal = ({
|
||||
term?.write('\x1bc');
|
||||
disposables.forEach(disposable => disposable.dispose());
|
||||
disposables.length = 0;
|
||||
|
||||
outputForScreenReader.textContent = '';
|
||||
};
|
||||
registerTerminal({ print, input, reset });
|
||||
}
|
||||
@ -103,7 +125,7 @@ export const XtermTerminal = ({
|
||||
return () => {
|
||||
term?.dispose();
|
||||
};
|
||||
}, [xtermFitRef]);
|
||||
}, [xtermFitRef, t]);
|
||||
|
||||
useEffect(() => {
|
||||
if (xtermFitRef.current) xtermFitRef.current.fit();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user