Skip to content

Commit e713257

Browse files
Menu: clear focusedElement on submenu hiding (T1291581) (#29854)
1 parent adc395d commit e713257

File tree

3 files changed

+77
-9
lines changed

3 files changed

+77
-9
lines changed

packages/devextreme/js/__internal/ui/context_menu/m_menu_base.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ const DX_ICON_WITH_URL_CLASS = 'dx-icon-with-url';
3838
const ITEM_URL_CLASS = 'dx-item-url';
3939

4040
// @ts-expect-error ts-error
41-
export type Properties = dxMenuBaseOptions<MenuBase, Item>;
41+
export interface Properties extends dxMenuBaseOptions<MenuBase, Item> {
42+
focusedElement?: dxElementWrapper;
43+
}
4244

4345
class MenuBase extends HierarchicalCollectionWidget<Properties> {
4446
static ItemClass = MenuItem;

packages/devextreme/js/__internal/ui/menu/m_menu.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class Menu extends MenuBase {
6464

6565
_submenus!: Submenu[];
6666

67-
_visibleSubmenu?: Submenu;
67+
_visibleSubmenu?: Submenu | null;
6868

6969
_overlay!: dxOverlay<OverlayProperties>;
7070

@@ -264,7 +264,6 @@ class Menu extends MenuBase {
264264
}
265265

266266
_initMarkup(): void {
267-
// @ts-expect-error
268267
this._visibleSubmenu = null;
269268

270269
this.$element().addClass(DX_MENU_CLASS);
@@ -693,9 +692,20 @@ class Menu extends MenuBase {
693692

694693
this._actions.onSubmenuHiding(eventArgs);
695694

695+
const { focusedElement } = this.option();
696+
const { focusedElement: submenuFocusedElement } = submenu.option();
697+
698+
const isVisibleSubmenuHiding = this._visibleSubmenu === submenu;
699+
const isFocusedElementHiding = focusedElement === submenuFocusedElement;
700+
701+
if (isVisibleSubmenuHiding && isFocusedElementHiding) {
702+
this.option('focusedElement', $menuAnchorItem);
703+
}
704+
696705
if (!eventArgs.cancel) {
697-
// @ts-expect-error
698-
if (this._visibleSubmenu === submenu) this._visibleSubmenu = null;
706+
if (isVisibleSubmenuHiding) {
707+
this._visibleSubmenu = null;
708+
}
699709
$border.hide();
700710
$menuAnchorItem.removeClass(DX_MENU_ITEM_EXPANDED_CLASS);
701711
}
@@ -904,7 +914,6 @@ class Menu extends MenuBase {
904914
}
905915

906916
if (this._visibleSubmenu === submenu) {
907-
// @ts-expect-error
908917
this._visibleSubmenu = null;
909918
}
910919
// @ts-expect-error

packages/devextreme/testing/tests/DevExpress.ui.widgets/menu.tests.js

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2584,7 +2584,6 @@ QUnit.module('keyboard navigation', {
25842584
itemClickHandler.resetHistory();
25852585

25862586
this.keyboard
2587-
.press('down')
25882587
.press('down')
25892588
.press('right')
25902589
.press('down')
@@ -2631,10 +2630,12 @@ QUnit.module('keyboard navigation', {
26312630
.press('down')
26322631
.press('down')
26332632
.press('down')
2634-
.press('down')
2635-
.press('space');
2633+
.press('down');
26362634

26372635
assert.equal(isRenderer(this.instance.option('focusedElement')), !!config().useJQuery, 'focusedElement is correct');
2636+
2637+
this.keyboard.press('space');
2638+
26382639
assert.equal(this.instance.option('selectedItem').text, 'item2-3', 'correct item is selected');
26392640
});
26402641

@@ -2947,6 +2948,62 @@ QUnit.module('keyboard navigation', {
29472948

29482949
assert.equal($(this.instance._visibleSubmenu.option('focusedElement')).text(), 'Item 113');
29492950
});
2951+
2952+
QUnit.test('focusedElement should be set to main menu item after hiding submenu', function(assert) {
2953+
this.instance.option({
2954+
orientation: 'horizontal',
2955+
items: [
2956+
{
2957+
text: 'Item 1',
2958+
items: [
2959+
{ text: 'Item 11', items: [ { text: 'Item 111' }, { text: 'Item 112' }, { text: 'Item 113' } ] },
2960+
{ text: 'Item 12' }
2961+
],
2962+
},
2963+
]
2964+
});
2965+
2966+
this.keyboard.press('enter')
2967+
.press('down')
2968+
.press('down');
2969+
2970+
assert.strictEqual($(this.instance.option('focusedElement')).text(), 'Item 12', 'focusedElement is submenu item');
2971+
2972+
this.keyboard.press('enter');
2973+
2974+
const mainMenuItemText = $(this.instance.itemElements()[0]).text();
2975+
2976+
assert.strictEqual($(this.instance.option('focusedElement')).text(), mainMenuItemText, 'focusedElement is main menu item');
2977+
});
2978+
2979+
QUnit.test('focusedElement should be set to main menu item after hiding nested submenu', function(assert) {
2980+
this.instance.option({
2981+
orientation: 'horizontal',
2982+
items: [
2983+
{
2984+
text: 'Item 1',
2985+
items: [
2986+
{ text: 'Item 11', items: [ { text: 'Item 111' }, { text: 'Item 112' }, { text: 'Item 113' } ] },
2987+
{ text: 'Item 12' }
2988+
],
2989+
},
2990+
]
2991+
});
2992+
2993+
this.keyboard.press('enter')
2994+
.press('down')
2995+
.press('enter')
2996+
.press('right')
2997+
.press('down');
2998+
2999+
assert.strictEqual($(this.instance.option('focusedElement')).text(), 'Item 112', 'focusedElement is submenu item');
3000+
3001+
this.keyboard.press('enter');
3002+
3003+
const mainMenuItemText = $(this.instance.itemElements()[0]).text();
3004+
3005+
assert.strictEqual($(this.instance.option('focusedElement')).text(), mainMenuItemText, 'focusedElement is main menu item');
3006+
});
29503007
});
29513008

29523009
QUnit.module('Menu with templates', {

0 commit comments

Comments
 (0)