Handle keyboard navigation

Signed-off-by: Jonathan <contact@grafikart.fr>
This commit is contained in:
Jonathan
2025-11-13 20:01:37 +01:00
committed by Émile Ré
parent 94684e56ff
commit 218566505b
3 changed files with 81 additions and 10 deletions

View File

@@ -24,12 +24,59 @@ export function downloadFile(url: string | undefined | null, filename: string) {
export function safeOpenUrl(url: string) {
try {
const parsedUrl = new URL(url);
if (parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:') {
window.open(url, '_blank', 'noopener,noreferrer');
if (parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:") {
window.open(url, "_blank", "noopener,noreferrer");
} else {
console.error('Invalid URL protocol. Only HTTP and HTTPS URLs are allowed:', url);
console.error(
"Invalid URL protocol. Only HTTP and HTTPS URLs are allowed:",
url,
);
}
} catch (error) {
console.error('Invalid URL format:', url, error);
console.error("Invalid URL format:", url, error);
}
}
export function focusSiblingElement(direction = 1) {
const current = document.activeElement as HTMLElement;
// Selector for all focusable elements
const focusableSelector = [
"a[href]",
"button:not([disabled])",
"input:not([disabled])",
"select:not([disabled])",
"textarea:not([disabled])",
'[tabindex]:not([tabindex="-1"])',
'[contenteditable="true"]',
].join(", ");
// Get all focusable elements in the document
const focusableElements = Array.from(
document.querySelectorAll<HTMLElement>(focusableSelector),
).filter((el) => {
// Filter out elements that are not visible or have display: none
const style = window.getComputedStyle(el);
return (
style.display !== "none" &&
style.visibility !== "hidden" &&
el.offsetParent !== null
);
});
const currentIndex = focusableElements.indexOf(current);
let nextIndex = currentIndex + direction;
if (nextIndex >= focusableElements.length || nextIndex < 0) {
return null;
}
const nextElement = focusableElements[nextIndex];
if (nextElement) {
nextElement.focus();
return nextElement;
}
return null;
}

View File

@@ -6,7 +6,12 @@ export {
getRiskLikelihoods,
getSeverity,
} from "./risk";
export { withViewTransition, downloadFile, safeOpenUrl } from "./dom";
export {
withViewTransition,
downloadFile,
safeOpenUrl,
focusSiblingElement,
} from "./dom";
export { times, groupBy, isEmpty } from "./array";
export { randomInt } from "./number";
export { getMeasureStateLabel, measureStates } from "./measure";