mirror of
https://github.com/getredash/redash.git
synced 2025-12-19 17:37:19 -05:00
Fix Ace editor keyboard trap (#5451)
* bug: fix a11y and add sr notification * refactor: improvements to sr notification
This commit is contained in:
@@ -2,6 +2,7 @@ import React, { useEffect, useMemo, useState, useCallback, useImperativeHandle }
|
||||
import PropTypes from "prop-types";
|
||||
import cx from "classnames";
|
||||
import { AceEditor, snippetsModule, updateSchemaCompleter } from "./ace";
|
||||
import { srNotify } from "@/lib/accessibility";
|
||||
import { SchemaItemType } from "@/components/queries/SchemaBrowser";
|
||||
import resizeObserver from "@/services/resizeObserver";
|
||||
import QuerySnippet from "@/services/query-snippet";
|
||||
@@ -89,6 +90,25 @@ const QueryEditor = React.forwardRef(function(
|
||||
// Lineup only mac
|
||||
editor.commands.bindKey({ win: null, mac: "Ctrl+P" }, "golineup");
|
||||
|
||||
// Esc for exiting
|
||||
editor.commands.bindKey({ win: "Esc", mac: "Esc" }, () => {
|
||||
editor.blur();
|
||||
});
|
||||
|
||||
let notificationCleanup = null;
|
||||
editor.on("focus", () => {
|
||||
notificationCleanup = srNotify({
|
||||
text: "You've entered the SQL editor. To exit press the ESC key.",
|
||||
politeness: "assertive",
|
||||
});
|
||||
});
|
||||
|
||||
editor.on("blur", () => {
|
||||
if (notificationCleanup) {
|
||||
notificationCleanup();
|
||||
}
|
||||
});
|
||||
|
||||
// Reset Completer in case dot is pressed
|
||||
editor.commands.on("afterExec", e => {
|
||||
if (e.command.name === "insertstring" && e.args === "." && editor.completer) {
|
||||
|
||||
45
client/app/lib/accessibility.ts
Normal file
45
client/app/lib/accessibility.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { HTMLAttributes } from "react";
|
||||
|
||||
interface SrNotifyProps {
|
||||
text: string;
|
||||
expiry: number;
|
||||
container: HTMLElement;
|
||||
politeness: HTMLAttributes<HTMLDivElement>["aria-live"];
|
||||
}
|
||||
|
||||
export function srNotify({ text, expiry = 1000, container = document.body, politeness = "polite" }: SrNotifyProps) {
|
||||
const element = document.createElement("div");
|
||||
const id = `speak-${Date.now()}`;
|
||||
|
||||
element.id = id;
|
||||
element.className = "sr-only";
|
||||
element.textContent = text;
|
||||
|
||||
element.setAttribute("role", "alert");
|
||||
element.setAttribute("aria-live", politeness);
|
||||
|
||||
container.appendChild(element);
|
||||
|
||||
let timer: null | number = null;
|
||||
let isDone = false;
|
||||
const cleanupFn = () => {
|
||||
if (isDone) {
|
||||
return;
|
||||
}
|
||||
isDone = true;
|
||||
|
||||
try {
|
||||
container.removeChild(element);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
if (timer) {
|
||||
window.clearTimeout(timer);
|
||||
}
|
||||
};
|
||||
|
||||
timer = window.setTimeout(cleanupFn, expiry);
|
||||
|
||||
return cleanupFn;
|
||||
}
|
||||
Reference in New Issue
Block a user