diff --git a/spec/__snapshots__/menu-button.spec.tsx.snap b/spec/__snapshots__/menu-button.spec.tsx.snap index 783e7c45..8befe9f8 100644 --- a/spec/__snapshots__/menu-button.spec.tsx.snap +++ b/spec/__snapshots__/menu-button.spec.tsx.snap @@ -9,6 +9,7 @@ exports[`Menu Button should show all elements 1`] = ` className="menu-button" data-testid="undefined_MENU_BUTTON" onClick={[Function]} + onKeyUp={[Function]} > Open menu { await waitForPromisesToResolve(); expect(wrapper.find('.menu').exists()).toBeFalsy(); }); + + it('should focus menu list on up', async () => { + const wrapper = mount( + , + ); + + wrapper.find('[data-testid="snipping-tool_MENU_BUTTON"]').simulate('click'); + wrapper.update(); + wrapper + .find('[data-testid="snipping-tool_MENU_BUTTON"]') + .simulate('keyup', { key: 'ArrowUp' }); + wrapper.update(); + expect( + (wrapper.find('[data-testid="snipping-tool_SAVE_AS"]').instance() as any) + .dataset.isfocused, + ).toBe('true'); + }); + + it('should focus menu list on down', async () => { + const wrapper = mount( + , + ); + + wrapper.find('[data-testid="snipping-tool_MENU_BUTTON"]').simulate('click'); + wrapper.update(); + wrapper + .find('[data-testid="snipping-tool_MENU_BUTTON"]') + .simulate('keyup', { key: 'ArrowDown' }); + wrapper.update(); + expect( + ( + wrapper + .find('[data-testid="snipping-tool_COPY_TO_CLIPBOARD"]') + .instance() as any + ).dataset.isfocused, + ).toBe('true'); + }); + + it('should go down on press down', async () => { + const wrapper = mount( + , + ); + + wrapper.find('[data-testid="snipping-tool_MENU_BUTTON"]').simulate('click'); + wrapper.update(); + wrapper + .find('[data-testid="snipping-tool_MENU_BUTTON"]') + .simulate('keyup', { key: 'ArrowDown' }); + wrapper.update(); + wrapper + .find('[data-testid="snipping-tool_LIST"]') + .simulate('keyup', { key: 'ArrowDown' }); + wrapper.update(); + expect( + (wrapper.find('[data-testid="snipping-tool_SAVE_AS"]').instance() as any) + .dataset.isfocused, + ).toBe('true'); + }); + + it('should go up on press up', async () => { + const wrapper = mount( + , + ); + + wrapper.find('[data-testid="snipping-tool_MENU_BUTTON"]').simulate('click'); + wrapper.update(); + wrapper + .find('[data-testid="snipping-tool_MENU_BUTTON"]') + .simulate('keyup', { key: 'ArrowUp' }); + wrapper + .find('[data-testid="snipping-tool_LIST"]') + .simulate('keyup', { key: 'ArrowUp' }); + wrapper.update(); + expect( + ( + wrapper + .find('[data-testid="snipping-tool_COPY_TO_CLIPBOARD"]') + .instance() as any + ).dataset.isfocused, + ).toBe('true'); + }); }); diff --git a/src/renderer/components/menu-button.tsx b/src/renderer/components/menu-button.tsx index f91799c5..e331503b 100644 --- a/src/renderer/components/menu-button.tsx +++ b/src/renderer/components/menu-button.tsx @@ -16,6 +16,8 @@ const MenuButton: React.FunctionComponent = ({ }) => { //#region State const [isDisplay, setDisplay] = useState(false); + const [currentFocusedItem, setCurrentFocusedItem] = + useState(); const listRef = useRef(document.createElement('div')); const menuButtonRef = useRef( document.createElement('button'), @@ -25,6 +27,7 @@ const MenuButton: React.FunctionComponent = ({ //#region Variables const testId = { menu: `${id}_MENU_BUTTON`, + list: `${id}_LIST`, }; //#endregion @@ -32,6 +35,55 @@ const MenuButton: React.FunctionComponent = ({ const onClickMenuButton = () => { setDisplay(!isDisplay); }; + + const onMenuKeyUp = (event: React.KeyboardEvent) => { + let item: HTMLButtonElement | null = null; + + if (event.key === 'ArrowDown') { + item = listRef.current.children[0] as HTMLButtonElement; + } + + if (event.key === 'ArrowUp') { + item = listRef.current.children[ + listRef.current.children.length - 1 + ] as HTMLButtonElement; + } + + if (item) { + item.focus(); + item.setAttribute('data-isfocused', 'true'); // UT Purpose + setCurrentFocusedItem(item); + } + }; + + const onListKeyUp = (event: React.KeyboardEvent) => { + let item: HTMLButtonElement | null = null; + if (!listRef.current) { + return; + } + + currentFocusedItem?.setAttribute('data-isfocused', 'false'); // UT Purpose + + if (event.key === 'ArrowUp') { + item = + (currentFocusedItem?.previousElementSibling as HTMLButtonElement) || + (listRef.current.children[ + listRef.current.children.length - 1 + ] as HTMLButtonElement); + } + + if (event.key === 'ArrowDown') { + item = + (currentFocusedItem?.nextElementSibling as HTMLButtonElement) || + (listRef.current.children[0] as HTMLButtonElement); + } + + if (item) { + item.focus(); + item.setAttribute('data-isfocused', 'true'); // UT Purpose + setCurrentFocusedItem(item); + } + }; //#endregion //#region UseEffect @@ -94,6 +146,7 @@ const MenuButton: React.FunctionComponent = ({ <>
{isDisplay && ( -
+
{renderListItems()}
)}