Handle keyboard navigation
Signed-off-by: Jonathan <contact@grafikart.fr>
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
Reference in New Issue
Block a user