-
Notifications
You must be signed in to change notification settings - Fork 672
Toolbar: support keyboard navigation according to APG W3C #33578
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
EugeniyKiyashko
wants to merge
26
commits into
DevExpress:26_1
Choose a base branch
from
EugeniyKiyashko:26_1_toolbar_kbn
base: 26_1
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
975def9
Toolbar: support keyboard navigation according to APG W3C
EugeniyKiyashko 957caf0
fix Copilot remarks
EugeniyKiyashko 841b6fb
Merge branch '26_1' into 26_1_toolbar_kbn
pharret31 319c6ec
Merge branch '26_1' into 26_1_toolbar_kbn
pharret31 d1577d8
Merge branch '26_1' into 26_1_toolbar_kbn
pharret31 119c52d
fix copilot's review issues
pharret31 e96abeb
revert default behavior to DataGrid demos
dmlvr 2202e7d
remove wa from e2e tests
dmlvr 440ad6d
leftovers
dmlvr 1321dfb
leftovers
dmlvr ce9ad6f
update etalons
dmlvr ce8065f
add more etalons
dmlvr 9128adc
Merge branch '26_1' into 26_1_toolbar_kbn
dmlvr 6060967
remove import
dmlvr 4547048
Merge branch '26_1_toolbar_kbn' of github.com:EugeniyKiyashko/DevExtr…
dmlvr 8f16cd1
update import
dmlvr 18ceedd
update etalon
dmlvr ecba17a
set global rtlEnabled
dmlvr d2cc260
remove test.only
dmlvr dcac03f
revert global rtl
dmlvr 07e73ce
allowKeyboardNavigation: false for DataGrid's groupPanel
dmlvr 334e271
add early return when modifier button used
dmlvr 0a286f6
revert some etalons
dmlvr 3c5c413
update early return for commandKey
dmlvr c1cda02
add testcases for grid group panel
dmlvr 1f49738
Merge branch '26_1' into 26_1_toolbar_kbn
dmlvr File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Binary file modified
BIN
-2.07 KB
(97%)
...widgets/datagrid/etalons/toolbar_customization_medium (material.blue.light).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
-774 Bytes
(98%)
...g/widgets/datagrid/etalons/toolbar_customization_thin (material.blue.light).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
-2.58 KB
(93%)
...ets/toolbar/etalons/toolbar_singleline_mode_menu_open (material.blue.light).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+219 Bytes
(100%)
...Reordering/etalons/column-separator-with-expand-columns (fluent.blue.light).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+253 Bytes
(100%)
...dering/etalons/dragging_grouped_column_to_same_position (fluent.blue.light).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+56 Bytes
(100%)
...Grid/common/etalons/grid-export-dropdown-button-in-menu (fluent.blue.light).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
-201 Bytes
(99%)
.../dataGrid/common/etalons/grid-export-one-button-in-menu (fluent.blue.light).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+13 Bytes
(100%)
...ns/reorder_group_column_to_left_when_rtlEnabled_=_false (fluent.blue.light).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+11 Bytes
(100%)
...ons/reorder_group_column_to_left_when_rtlEnabled_=_true (fluent.blue.light).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+12 Bytes
(100%)
...s/reorder_group_column_to_right_when_rtlEnabled_=_false (fluent.blue.light).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+11 Bytes
(100%)
...ns/reorder_group_column_to_right_when_rtlEnabled_=_true (fluent.blue.light).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+12 Bytes
(100%)
...up_column_when_group_panel_allowColumnDragging_is_false (fluent.blue.light).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+12 Bytes
(100%)
...reorder_group_column_when_onKeyDown_args_handled_=_true (fluent.blue.light).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+12 Bytes
(100%)
...talons/reorder_group_column_with_allowGrouping_is_false (fluent.blue.light).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
-156 Bytes
(98%)
...dNavigation/etalons/ungroup_column_when_pressing_delete (fluent.blue.light).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+226 Bytes
(100%)
.../common/etalons/header_row_highlight_with_fixed_columns (fluent.blue.light).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+4.22 KB
...lbar RTL focus border visible after keyboard navigation (fluent.blue.light).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+3.68 KB
...r/etalons/Toolbar RTL no focus border after mouse click (fluent.blue.light).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+5.97 KB
...tem after Arrow-Home-End navigation with disabled items (fluent.blue.light).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
170 changes: 170 additions & 0 deletions
170
e2e/testcafe-devextreme/tests/navigation/toolbar/keyboard.nonAPG.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,170 @@ | ||
| import { ClientFunction, Selector } from 'testcafe'; | ||
| import Toolbar from 'devextreme-testcafe-models/toolbar/toolbar'; | ||
| import url from '../../../helpers/getPageUrl'; | ||
| import { createWidget } from '../../../helpers/createWidget'; | ||
| import { appendElementTo } from '../../../helpers/domUtils'; | ||
|
|
||
| fixture.disablePageReloads`Toolbar_keyboard_navigation_nonAPG` | ||
| .page(url(__dirname, '../../container.html')); | ||
|
|
||
| const itemHasFocus = (item: Selector): Selector => item.filter( | ||
| (node) => node === document.activeElement | ||
| || node.contains(document.activeElement as Node | null), | ||
| ); | ||
|
|
||
| const setupThreeButtonsFixture = async (): Promise<void> => { | ||
| await appendElementTo('#container', 'div', 'externalBefore'); | ||
| await appendElementTo('#container', 'div', 'toolbar'); | ||
| await appendElementTo('#container', 'div', 'externalAfter'); | ||
|
|
||
| await createWidget('dxButton', { text: 'External Before' }, '#externalBefore'); | ||
|
|
||
| await createWidget('dxToolbar', { | ||
| allowKeyboardNavigation: false, | ||
| items: [ | ||
| { | ||
| location: 'before', | ||
| widget: 'dxButton', | ||
| options: { text: 'A', focusStateEnabled: true }, | ||
| }, | ||
| { | ||
| location: 'before', | ||
| widget: 'dxButton', | ||
| options: { text: 'B', focusStateEnabled: true }, | ||
| }, | ||
| { | ||
| location: 'before', | ||
| widget: 'dxButton', | ||
| options: { text: 'C', focusStateEnabled: true }, | ||
| }, | ||
| ], | ||
| }, '#toolbar'); | ||
|
|
||
| await createWidget('dxButton', { text: 'External After' }, '#externalAfter'); | ||
| }; | ||
|
|
||
| test('Tab walks through every toolbar item; Shift+Tab walks back', async (t) => { | ||
| const externalBefore = Selector('#externalBefore'); | ||
| const externalAfter = Selector('#externalAfter'); | ||
| const toolbar = new Toolbar('#toolbar'); | ||
|
|
||
| await t.click(externalBefore); | ||
| await t.expect(externalBefore.focused).ok('external before is focused'); | ||
|
|
||
| await t.pressKey('tab'); | ||
| await t.expect(itemHasFocus(toolbar.getItem(0)).exists) | ||
| .ok('Tab #1 -> item[0]'); | ||
|
|
||
| await t.pressKey('tab'); | ||
| await t.expect(itemHasFocus(toolbar.getItem(1)).exists) | ||
| .ok('Tab #2 -> item[1]'); | ||
|
|
||
| await t.pressKey('tab'); | ||
| await t.expect(itemHasFocus(toolbar.getItem(2)).exists) | ||
| .ok('Tab #3 -> item[2]'); | ||
|
|
||
| await t.pressKey('tab'); | ||
| await t.expect(externalAfter.focused) | ||
| .ok('Tab #4 -> external after'); | ||
|
|
||
| await t.pressKey('shift+tab'); | ||
| await t.expect(itemHasFocus(toolbar.getItem(2)).exists) | ||
| .ok('Shift+Tab #1 -> item[2]'); | ||
|
|
||
| await t.pressKey('shift+tab'); | ||
| await t.expect(itemHasFocus(toolbar.getItem(1)).exists) | ||
| .ok('Shift+Tab #2 -> item[1]'); | ||
|
|
||
| await t.pressKey('shift+tab'); | ||
| await t.expect(itemHasFocus(toolbar.getItem(0)).exists) | ||
| .ok('Shift+Tab #3 -> item[0]'); | ||
|
|
||
| await t.pressKey('shift+tab'); | ||
| await t.expect(externalBefore.focused) | ||
| .ok('Shift+Tab #4 -> external before'); | ||
| }).before(setupThreeButtonsFixture); | ||
|
|
||
| test('Arrow keys do not move focus across toolbar items', async (t) => { | ||
| const externalBefore = Selector('#externalBefore'); | ||
| const toolbar = new Toolbar('#toolbar'); | ||
|
|
||
| await t.click(externalBefore); | ||
| await t.pressKey('tab'); | ||
| await t.expect(itemHasFocus(toolbar.getItem(0)).exists) | ||
| .ok('item[0] focused'); | ||
|
|
||
| const keys = ['right', 'left', 'home', 'end', 'down', 'up']; | ||
| await keys.reduce(async (prev, key) => { | ||
| await prev; | ||
| await t.pressKey(key); | ||
| await t.expect(itemHasFocus(toolbar.getItem(0)).exists) | ||
| .ok(`focus stays on item[0] after "${key}"`); | ||
| await t.expect(itemHasFocus(toolbar.getItem(1)).exists) | ||
| .notOk(`focus does not jump to item[1] on "${key}"`); | ||
| }, Promise.resolve()); | ||
| }).before(setupThreeButtonsFixture); | ||
|
|
||
| const getTabsSelectedIndex = ClientFunction( | ||
| () => ($('#toolbar .dx-tabs') as unknown as { | ||
| dxTabs: (m: string, n: string) => number; | ||
| }).dxTabs('option', 'selectedIndex'), | ||
| ); | ||
|
|
||
| test('Arrow keys are forwarded to the focused widget (dxTabs changes selectedIndex)', async (t) => { | ||
| const externalBefore = Selector('#externalBefore'); | ||
| const toolbar = new Toolbar('#toolbar'); | ||
|
|
||
| await t.click(externalBefore); | ||
| await t.pressKey('tab tab'); | ||
| await t.expect(itemHasFocus(toolbar.getItem(1)).exists) | ||
| .ok('focus is inside dxTabs item'); | ||
|
|
||
| await t.expect(getTabsSelectedIndex()).eql(0, 'initial selectedIndex is 0'); | ||
|
|
||
| await t.pressKey('right'); | ||
| await t.expect(getTabsSelectedIndex()).eql( | ||
| 1, | ||
| 'ArrowRight reaches dxTabs and advances selectedIndex', | ||
| ); | ||
| await t.expect(itemHasFocus(toolbar.getItem(1)).exists) | ||
| .ok('focus stays inside dxTabs, did not jump to item[2]'); | ||
|
|
||
| await t.pressKey('left'); | ||
| await t.expect(getTabsSelectedIndex()).eql( | ||
| 0, | ||
| 'ArrowLeft reaches dxTabs and decreases selectedIndex', | ||
| ); | ||
| await t.expect(itemHasFocus(toolbar.getItem(1)).exists) | ||
| .ok('focus still inside dxTabs'); | ||
| }).before(async () => { | ||
| await appendElementTo('#container', 'div', 'externalBefore'); | ||
| await appendElementTo('#container', 'div', 'toolbar'); | ||
|
|
||
| await createWidget('dxButton', { text: 'External Before' }, '#externalBefore'); | ||
|
|
||
| await createWidget('dxToolbar', { | ||
| allowKeyboardNavigation: false, | ||
| items: [ | ||
| { | ||
| location: 'before', | ||
| widget: 'dxButton', | ||
| options: { text: 'Prev', focusStateEnabled: true }, | ||
| }, | ||
| { | ||
| location: 'before', | ||
| widget: 'dxTabs', | ||
| options: { | ||
| items: [{ text: 'Home' }, { text: 'Insert' }, { text: 'Layout' }], | ||
| selectedIndex: 0, | ||
| width: 'auto', | ||
| focusStateEnabled: true, | ||
| }, | ||
| }, | ||
| { | ||
| location: 'before', | ||
| widget: 'dxButton', | ||
| options: { text: 'Next', focusStateEnabled: true }, | ||
| }, | ||
| ], | ||
| }, '#toolbar'); | ||
| }); |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please recheck this case and 3 below - it seems the functionality changed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello, we found the reason, fix it and update etalons one more time, please, check it again