diff --git a/modules/web-common b/modules/web-common index 00f99acb..e3e2a7d5 160000 --- a/modules/web-common +++ b/modules/web-common @@ -1 +1 @@ -Subproject commit 00f99acb4b5e5319a3700114ced2df02db52fd70 +Subproject commit e3e2a7d59dd14ca91977f063248dd75daa72dc1e diff --git a/src/js/component/item/items/table.jsx b/src/js/component/item/items/table.jsx index 5e1a63f6..6956a3db 100644 --- a/src/js/component/item/items/table.jsx +++ b/src/js/component/item/items/table.jsx @@ -347,6 +347,11 @@ const Table = () => { }, [dispatch, isEmbedded, focusBySelector]); const handleTableFocus = useCallback(ev => { + // The overflow list is made focusable by default in most browsers and to prevent this we + // need to set `tabIndex` to -1. However, since this element is rendered by react-window, we + // cannot pass it as a prop. As a workaround, we set the tabIndex attribute directly here. + // This fixes issue #519. + outerRef.current?.setAttribute?.('tabindex', '-1'); const hasChangedFocused = receiveFocus(ev); if(hasChangedFocused) { dispatch(triggerFocus('items-table', true)); diff --git a/src/js/component/tag-selector/tag-selector-items.jsx b/src/js/component/tag-selector/tag-selector-items.jsx index 6f18ea95..f5816ca2 100644 --- a/src/js/component/tag-selector/tag-selector-items.jsx +++ b/src/js/component/tag-selector/tag-selector-items.jsx @@ -186,6 +186,7 @@ const TagSelectorItems = () => { return (
{ + delete window.location; + window.location = new URL('http://localhost/testuser/collections/WTTJ2J56/items/VR82JUX8/item-details'); + const user = userEvent.setup() + renderWithProviders(, { preloadedState: state, includeStyles: true }); + + await waitForPosition(); + await user.click(screen.getByRole('textbox', { name: 'Title' })); + expect(screen.getByRole('textbox', { name: 'Title' })).toHaveFocus(); + + await user.keyboard('{shift>}{tab}{/shift}'); + const inputTypeCombo = screen.getByRole('combobox', { name: 'Item Type' }); + expect(getByRole(inputTypeCombo, 'textbox')).toHaveFocus(); + + await user.keyboard('{shift>}{tab}{/shift}'); + expect(screen.getByRole('tab', { name: 'Info' })).toHaveFocus(); + + await user.keyboard('{shift>}{tab}{/shift}'); + expect(screen.getByRole('row', { name: 'Effects of diet restriction on life span and age-related changes in dogs' })).toHaveFocus(); + + await user.keyboard('{shift>}{tab}{/shift}'); + expect(screen.getByRole('button', { name: 'New Item' })).toHaveFocus(); + + await user.keyboard('{shift>}{tab}{/shift}'); + expect(screen.getByRole('searchbox', { name: 'Filter Tags' })).toHaveFocus(); + + await user.keyboard('{shift>}{tab}{/shift}'); + expect(screen.getByRole('button', { name: 'cute' })).toHaveFocus(); + + await user.keyboard('{shift>}{tab}{/shift}'); + expect(screen.getByRole('button', { name: 'Collapse Tag Selector' })).toHaveFocus(); + + await user.keyboard('{shift>}{tab}{/shift}'); + expect(screen.getByRole('treeitem', { name: 'My Library' })).toHaveFocus(); + + await user.keyboard('{shift>}{tab}{/shift}'); + expect(screen.getByRole('searchbox', { name: 'Title, Creator, Year' })).toHaveFocus(); +}); + + diff --git a/test/keyboard-ui.test.jsx b/test/keyboard-ui.test.jsx index b29176c6..2eff0a99 100644 --- a/test/keyboard-ui.test.jsx +++ b/test/keyboard-ui.test.jsx @@ -57,4 +57,16 @@ test('Tabulate through the UI', async () => { expect(screen.getAllByRole('combobox', { name: 'Creator Type' }).shift()).toHaveFocus(); }); +test('Tabbing back to item details tabs should focus on the last selected tab', async () => { + delete window.location; + window.location = new URL('http://localhost/testuser/collections/WTTJ2J56/items/VR82JUX8/item-details'); + const user = userEvent.setup() + renderWithProviders(, { preloadedState: state, includeStyles: true }); + await user.click(screen.getByRole('tab', { name: 'Tags' })); + await user.keyboard('{tab}'); + expect(screen.getByRole('button', { name: 'Add Tag' })).toHaveFocus(); + + await user.keyboard('{shift>}{tab}{/shift}'); + expect(screen.getByRole('tab', { name: 'Tags' })).toHaveFocus(); +});