admin管理员组文章数量:1405170
I am building a context menu with support for escape and navigation keys. However, I've noticed that if I open the context menu for the first time, the arrow navigation keys work perfectly; however, if I open it by the second time, the arrow navigation keys work in reverse order (a bug in my logic?). If I open it more times, it bugs totally and may not work anymore.
Playground
Here are related code parts:
(navigation on outermost context menu)
for (let i = 0; i < div.children.length; i++)
{
// Child (item or submenu)
const child = div.children[i] as HTMLElement;
// If focused
if (document.activeElement === child)
{
// navigate up
if (Input.input.justPressed("navigateUp"))
{
focusPrevSibling(child);
}
// navigate down
else if (Input.input.justPressed("navigateDown"))
{
focusNextSibling(child);
}
// open submenu
else if (Input.input.justPressed(localeDir == "ltr" ? "navigateRight" : "navigateLeft") && child.classList.contains(submenuItemClassName))
{
(child as HTMLButtonElement).click();
}
return;
}
}
(focusability utils)
/**
* Focus the previous focusable sibling of an element.
*/
export function focusPrevSibling(element: HTMLElement): void
{
const parent = element.parentElement;
const children = Array.from(parent.children) as HTMLElement[];
const i = children.indexOf(element);
const list = children.slice(0, i).reverse().concat(children.slice(i + 1).reverse());
const firstFocusable = list.find(e => canFocus(e));
if (firstFocusable)
{
(firstFocusable as HTMLElement).focus();
}
}
/**
* Focus the next focusable sibling of an element.
*/
export function focusNextSibling(element: HTMLElement): void
{
const parent = element.parentElement;
const children = Array.from(parent.children) as HTMLElement[];
const i = children.indexOf(element);
const list = children.slice(i + 1).concat(children.slice(0, i + 1));
const firstFocusable = list.find(e => canFocus(e));
if (firstFocusable)
{
(firstFocusable as HTMLElement).focus();
}
}
The problem here is basically that these functions like focusNextSibling
are messed up next open up times. The firstFocusable
that comes out is wrong in past opens.
It does seem to have to do with the Input.input
event listeners that get accumulated, because since when I press for example down
it outputs multiple console.log
s gradually more each time I re-open the context menu; however, I have now done removeEventListener
before addEventListener
and it doesn't seem to work still (it keeps accumulating).
I am building a context menu with support for escape and navigation keys. However, I've noticed that if I open the context menu for the first time, the arrow navigation keys work perfectly; however, if I open it by the second time, the arrow navigation keys work in reverse order (a bug in my logic?). If I open it more times, it bugs totally and may not work anymore.
Playground
Here are related code parts:
(navigation on outermost context menu)
for (let i = 0; i < div.children.length; i++)
{
// Child (item or submenu)
const child = div.children[i] as HTMLElement;
// If focused
if (document.activeElement === child)
{
// navigate up
if (Input.input.justPressed("navigateUp"))
{
focusPrevSibling(child);
}
// navigate down
else if (Input.input.justPressed("navigateDown"))
{
focusNextSibling(child);
}
// open submenu
else if (Input.input.justPressed(localeDir == "ltr" ? "navigateRight" : "navigateLeft") && child.classList.contains(submenuItemClassName))
{
(child as HTMLButtonElement).click();
}
return;
}
}
(focusability utils)
/**
* Focus the previous focusable sibling of an element.
*/
export function focusPrevSibling(element: HTMLElement): void
{
const parent = element.parentElement;
const children = Array.from(parent.children) as HTMLElement[];
const i = children.indexOf(element);
const list = children.slice(0, i).reverse().concat(children.slice(i + 1).reverse());
const firstFocusable = list.find(e => canFocus(e));
if (firstFocusable)
{
(firstFocusable as HTMLElement).focus();
}
}
/**
* Focus the next focusable sibling of an element.
*/
export function focusNextSibling(element: HTMLElement): void
{
const parent = element.parentElement;
const children = Array.from(parent.children) as HTMLElement[];
const i = children.indexOf(element);
const list = children.slice(i + 1).concat(children.slice(0, i + 1));
const firstFocusable = list.find(e => canFocus(e));
if (firstFocusable)
{
(firstFocusable as HTMLElement).focus();
}
}
The problem here is basically that these functions like focusNextSibling
are messed up next open up times. The firstFocusable
that comes out is wrong in past opens.
It does seem to have to do with the Input.input
event listeners that get accumulated, because since when I press for example down
it outputs multiple console.log
s gradually more each time I re-open the context menu; however, I have now done removeEventListener
before addEventListener
and it doesn't seem to work still (it keeps accumulating).
1 Answer
Reset to default 0The only solution I have found is to have a global Input.input.addEventListener()
call (rather than adding an event listener per context menu) and through it call a global callback that is updated by the context menus.
// Weak map mapping to Input listeners of submenus reliably.
// The keys are the submenu lists themselves, not the submenu representing items.
const submenuInputPressedListeners = new WeakMap<HTMLDivElement, Function>();
// Globalized input action listener
Input.input.addEventListener("inputPressed", function(): void
{
currentInputPressedListener?.();
});
(Updated with either currentInputPressedListener = input_onInputPressed;
or currentInputPressedListener = null;
, instead of Input.input.addEventListener
or removeEventListener
)
Now am I doing this to test navigation input on submenus from outer context menus:
// Check input on submenu
submenuInputPressedListeners.get(submenus[submenus.length - 1])();
本文标签: reactjsCustom context menu is messing up children in navigationStack Overflow
版权声明:本文标题:reactjs - Custom context menu is messing up children in navigation - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744886022a2630490.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论