Skip to content

Commit

Permalink
Fix search navigation with narrator, closes #2563
Browse files Browse the repository at this point in the history
  • Loading branch information
Gerrit0 committed May 2, 2024
1 parent f4811e5 commit e30ed7a
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 28 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -30,6 +30,7 @@
- Links added with the `navigationLinks` option are now moved into the pull out navigation on mobile displays, #2548.
- `@license` and `@import` comments will be ignored at the top of files, #2552.
- Fixed issue in documentation validation where constructor signatures where improperly considered not documented, #2553.
- Fixed issue where search results could not be navigated while Windows Narrator was on, #2563.

### Thanks!

Expand Down
22 changes: 21 additions & 1 deletion scripts/build_themes.js
@@ -1,5 +1,24 @@
// @ts-check
const esbuild = require("esbuild");
const fs = require("fs");

const watch = process.argv.slice(2).includes("--watch");

// It's convenient to be able to build the themes in watch mode without rebuilding the whole docs
// to test some change to the frontend JS.
/** @type {esbuild.Plugin} */
const copyToDocsPlugin = {
name: "copyToDocs",
setup(build) {
if (watch) {
build.onEnd(() => {
if (fs.existsSync("docs/assets/main.js")) {
fs.copyFileSync("static/main.js", "docs/assets/main.js");
}
});
}
},
};

async function main() {
const context = await esbuild.context({
Expand All @@ -11,11 +30,12 @@ async function main() {
js: '"use strict";',
},
logLevel: "info",
plugins: [copyToDocsPlugin],
});

await context.rebuild();

if (process.argv.slice(2).includes("--watch")) {
if (watch) {
await context.watch();
} else {
await context.dispose();
Expand Down
65 changes: 38 additions & 27 deletions src/lib/output/themes/default/assets/typedoc/components/Search.ts
Expand Up @@ -80,20 +80,11 @@ export function initSearch() {
);
}

let resultClicked = false;
results.addEventListener("mousedown", () => (resultClicked = true));
results.addEventListener("mouseup", () => {
resultClicked = false;
searchEl.classList.remove("has-focus");
hideSearch(searchEl);
});

field.addEventListener("focus", () => searchEl.classList.add("has-focus"));
field.addEventListener("blur", () => {
if (!resultClicked) {
resultClicked = false;
searchEl.classList.remove("has-focus");
}
});

bindEvents(searchEl, results, field, state);
}
Expand All @@ -111,37 +102,45 @@ function bindEvents(
}, 200),
);

let preventPress = false;
// Narrator is a pain. It completely eats the up/down arrow key events, so we can't
// rely on detecting the input blurring to hide the focus. We have to instead check
// for a focus event on an item outside of the search field/results.
field.addEventListener("keydown", (e) => {
preventPress = true;
if (e.key == "Enter") {
gotoCurrentResult(results, field);
} else if (e.key == "Escape") {
field.blur();
gotoCurrentResult(results, searchEl);
} else if (e.key == "ArrowUp") {
setCurrentResult(results, -1);
setCurrentResult(results, field, -1);
e.preventDefault();
} else if (e.key === "ArrowDown") {
setCurrentResult(results, 1);
} else {
preventPress = false;
setCurrentResult(results, field, 1);
e.preventDefault();
}
});
field.addEventListener("keypress", (e) => {
if (preventPress) e.preventDefault();
});

/**
* Start searching by pressing slash.
*/
document.body.addEventListener("keydown", (e) => {
document.body.addEventListener("keyup", (e) => {
if (e.altKey || e.ctrlKey || e.metaKey) return;
if (!field.matches(":focus") && e.key === "/") {
field.focus();
e.preventDefault();
field.focus();
}
if (
searchEl.classList.contains("has-focus") &&
(e.key === "Escape" ||
(!results.matches(":focus-within") && !field.matches(":focus")))
) {
field.blur();
hideSearch(searchEl);
}
});
}

function hideSearch(searchEl: HTMLElement) {
searchEl.classList.remove("has-focus");
}

function updateResults(
searchEl: HTMLElement,
results: HTMLElement,
Expand Down Expand Up @@ -223,14 +222,23 @@ function updateResults(
anchor.innerHTML = icon + name;
item.append(anchor);

anchor.addEventListener("focus", () => {
results.querySelector(".current")?.classList.remove("current");
item.classList.add("current");
});

results.appendChild(item);
}
}

/**
* Move the highlight within the result set.
*/
function setCurrentResult(results: HTMLElement, dir: number) {
function setCurrentResult(
results: HTMLElement,
field: HTMLInputElement,
dir: number,
) {
let current = results.querySelector(".current");
if (!current) {
current = results.querySelector(
Expand All @@ -256,14 +264,17 @@ function setCurrentResult(results: HTMLElement, dir: number) {
if (rel) {
current.classList.remove("current");
rel.classList.add("current");
} else if (dir === -1) {
current.classList.remove("current");
field.focus();
}
}
}

/**
* Navigate to the highlighted result.
*/
function gotoCurrentResult(results: HTMLElement, field: HTMLInputElement) {
function gotoCurrentResult(results: HTMLElement, searchEl: HTMLElement) {
let current = results.querySelector(".current");

if (!current) {
Expand All @@ -275,7 +286,7 @@ function gotoCurrentResult(results: HTMLElement, field: HTMLInputElement) {
if (link) {
window.location.href = link.href;
}
field.blur();
hideSearch(searchEl);
}
}

Expand Down

0 comments on commit e30ed7a

Please sign in to comment.