fix(techdocs): ExpandableNavigation addons does not work on Firefox

Signed-off-by: Gabriel Dugny <gabriel.dugny@believe.com>
This commit is contained in:
Gabriel Dugny
2025-07-10 11:39:23 +02:00
parent 9749918bf6
commit 69294800c1
2 changed files with 59 additions and 49 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-techdocs-module-addons-contrib': patch
---
ExpandableCollapse Techdocs Addon was breaking native sidebar collapse on Firefox
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { useEffect, useCallback, useState } from 'react';
import { useEffect, useState } from 'react';
import { useLocalStorageValue } from '@react-hookz/web';
import { Button, withStyles } from '@material-ui/core';
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
@@ -73,71 +73,72 @@ export const ExpandableNavigationAddon = () => {
NESTED_LIST_TOGGLE,
]);
const shouldToggle = useCallback(
(item: HTMLInputElement) => {
const isExpanded = item.checked;
const shouldExpand = expanded?.expandAllNestedNavs;
// Is collapsed but should expand
if (shouldExpand && !isExpanded) {
return true;
}
// Is expanded but should collapse
if (!shouldExpand && isExpanded) {
return true;
}
return false;
},
[expanded],
);
const handleKeyPass = (
// Define handleKeyPass as a named function
function handleKeyPass(
event: React.KeyboardEvent<HTMLElement>,
toggleAction: () => void,
) => {
) {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
toggleAction();
}
};
useEffect(() => {
// There is no nested navs
if (!checkboxToggles?.length) return;
}
useEffect(() => {
if (!checkboxToggles?.length) return;
setHasNavSubLevels(true);
checkboxToggles.forEach(item => {
item.tabIndex = 0;
const toggleAction = () => {
if (shouldToggle(item)) {
item.click();
function createKeydownHandler(item: HTMLInputElement) {
return function handleKeydown(event: KeyboardEvent) {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
item.checked = !item.checked;
item.dispatchEvent(new Event('change', { bubbles: true }));
}
};
// Add keyboard event listener
const keydownHandler = (event: KeyboardEvent) => {
handleKeyPass(
event as unknown as React.KeyboardEvent<HTMLDivElement>,
toggleAction,
);
}
function createCleanup(
item: HTMLInputElement,
handler: (event: KeyboardEvent) => void,
) {
return function cleanup() {
item.removeEventListener('keydown', handler);
};
}
const cleanupFunctions: Array<() => void> = [];
for (const item of checkboxToggles) {
item.tabIndex = 0;
const keydownHandler = createKeydownHandler(item);
item.addEventListener('keydown', keydownHandler);
item.addEventListener('click', toggleAction);
cleanupFunctions.push(createCleanup(item, keydownHandler));
}
function cleanupAll() {
for (const cleanup of cleanupFunctions) {
cleanup();
}
}
// eslint-disable-next-line consistent-return
return cleanupAll;
}, [checkboxToggles, expanded]);
// Clean up event listener or unmount
return () => {
item.removeEventListener('keydown', keydownHandler);
item.removeEventListener('click', toggleAction);
};
});
}, [checkboxToggles, shouldToggle]);
useEffect(() => {
if (!checkboxToggles?.length) return;
checkboxToggles.forEach(item => {
function shouldToggle(item: HTMLInputElement) {
const isExpanded = item.checked;
const shouldExpand = expanded?.expandAllNestedNavs;
if (shouldExpand && !isExpanded) {
return true;
}
if (!shouldExpand && isExpanded) {
return true;
}
return false;
}
for (const item of checkboxToggles) {
if (shouldToggle(item)) {
item.click();
}
});
}, [expanded, checkboxToggles, shouldToggle]);
}
}, [expanded, checkboxToggles]);
const handleState = () => {
setExpanded(prevState => ({
@@ -145,13 +146,17 @@ export const ExpandableNavigationAddon = () => {
}));
};
function handleButtonKeyDown(event: React.KeyboardEvent<HTMLElement>) {
handleKeyPass(event, handleState);
}
return (
<>
{hasNavSubLevels ? (
<StyledButton
size="small"
onClick={handleState}
onKeyDown={event => handleKeyPass(event, handleState)}
onKeyDown={handleButtonKeyDown}
tabIndex={0} // Ensuring keyboard focus
aria-expanded={expanded?.expandAllNestedNavs} // Accessibility
aria-label={