Skip to content

Commit bb4afbf

Browse files
authored
refactor: inline submenu mixin, add button and submenu typings (#9928)
1 parent b3aa3ee commit bb4afbf

File tree

7 files changed

+116
-69
lines changed

7 files changed

+116
-69
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* @license
3+
* Copyright (c) 2019 - 2025 Vaadin Ltd.
4+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5+
*/
6+
import { Button } from '@vaadin/button/src/vaadin-button.js';
7+
8+
/**
9+
* An element used internally by `<vaadin-menu-bar>`. Not intended to be used separately.
10+
*/
11+
declare class MenuBarButton extends Button {}
12+
13+
declare global {
14+
interface HTMLElementTagNameMap {
15+
'vaadin-menu-bar-button': MenuBarButton;
16+
}
17+
}
18+
19+
export { MenuBarButton };

packages/menu-bar/src/vaadin-menu-bar-button.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,5 @@ class MenuBarButton extends Button {
5454
}
5555

5656
defineCustomElement(MenuBarButton);
57+
58+
export { MenuBarButton };

packages/menu-bar/src/vaadin-menu-bar-mixin.d.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type { KeyboardDirectionMixinClass } from '@vaadin/a11y-base/src/keyboard
1010
import type { KeyboardMixinClass } from '@vaadin/a11y-base/src/keyboard-mixin.js';
1111
import type { I18nMixinClass } from '@vaadin/component-base/src/i18n-mixin.js';
1212
import type { ResizeMixinClass } from '@vaadin/component-base/src/resize-mixin.js';
13+
import type { MenuBarButton } from './vaadin-menu-bar-button.js';
1314

1415
export type MenuBarItem<TItemData extends object = object> = {
1516
/**
@@ -159,11 +160,11 @@ export declare class MenuBarMixinClass<TItem extends MenuBarItem = MenuBarItem>
159160
*/
160161
close(): void;
161162

162-
protected readonly _buttons: HTMLElement[];
163+
protected readonly _buttons: MenuBarButton[];
163164

164165
protected readonly _container: HTMLElement;
165166

166-
protected readonly _overflow: HTMLElement;
167+
protected readonly _overflow: MenuBarButton;
167168

168169
protected _hasOverflow: boolean;
169170
}

packages/menu-bar/src/vaadin-menu-bar-submenu-mixin.js

Lines changed: 0 additions & 64 deletions
This file was deleted.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* @license
3+
* Copyright (c) 2019 - 2025 Vaadin Ltd.
4+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5+
*/
6+
import { ContextMenuMixin } from '@vaadin/context-menu/src/vaadin-context-menu-mixin.js';
7+
import { ThemePropertyMixin } from '@vaadin/vaadin-themable-mixin/vaadin-theme-property-mixin.js';
8+
9+
/**
10+
* An element used internally by `<vaadin-menu-bar>`. Not intended to be used separately.
11+
*/
12+
declare class MenuBarSubmenu extends ContextMenuMixin(ThemePropertyMixin(HTMLElement)) {}
13+
14+
declare global {
15+
interface HTMLElementTagNameMap {
16+
'vaadin-menu-bar-submenu': MenuBarSubmenu;
17+
}
18+
}
19+
20+
export { MenuBarSubmenu };

packages/menu-bar/src/vaadin-menu-bar-submenu.js

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,19 @@ import { css, html, LitElement } from 'lit';
1010
import { ifDefined } from 'lit/directives/if-defined.js';
1111
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
1212
import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
13+
import { ContextMenuMixin } from '@vaadin/context-menu/src/vaadin-context-menu-mixin.js';
1314
import { ThemePropertyMixin } from '@vaadin/vaadin-themable-mixin/vaadin-theme-property-mixin.js';
14-
import { SubMenuMixin } from './vaadin-menu-bar-submenu-mixin.js';
1515

1616
/**
1717
* An element used internally by `<vaadin-menu-bar>`. Not intended to be used separately.
1818
*
1919
* @customElement
2020
* @extends HTMLElement
21-
* @mixes SubMenuMixin
21+
* @mixes ContextMenuMixin
2222
* @mixes ThemePropertyMixin
2323
* @protected
2424
*/
25-
class MenuBarSubmenu extends SubMenuMixin(ThemePropertyMixin(PolylitMixin(LitElement))) {
25+
class MenuBarSubmenu extends ContextMenuMixin(ThemePropertyMixin(PolylitMixin(LitElement))) {
2626
static get is() {
2727
return 'vaadin-menu-bar-submenu';
2828
}
@@ -39,6 +39,21 @@ class MenuBarSubmenu extends SubMenuMixin(ThemePropertyMixin(PolylitMixin(LitEle
3939
`;
4040
}
4141

42+
constructor() {
43+
super();
44+
45+
this.openOn = 'opensubmenu';
46+
}
47+
48+
/**
49+
* Tag name prefix used by overlay, list-box and items.
50+
* @protected
51+
* @return {string}
52+
*/
53+
get _tagNamePrefix() {
54+
return 'vaadin-menu-bar';
55+
}
56+
4257
/** @protected */
4358
render() {
4459
return html`
@@ -61,6 +76,45 @@ class MenuBarSubmenu extends SubMenuMixin(ThemePropertyMixin(PolylitMixin(LitEle
6176
</vaadin-menu-bar-overlay>
6277
`;
6378
}
79+
80+
/**
81+
* Overriding the observer to not add global "contextmenu" listener.
82+
* @override
83+
*/
84+
_openedChanged() {
85+
// Do nothing
86+
}
87+
88+
/**
89+
* Overriding the public method to reset expanded button state.
90+
*/
91+
close() {
92+
super.close();
93+
94+
// Only handle 1st level submenu
95+
if (this.hasAttribute('is-root')) {
96+
this.parentElement._close();
97+
}
98+
}
99+
100+
/**
101+
* Override method from `ContextMenuMixin` to prevent closing
102+
* sub-menu on the same click event that was used to open it.
103+
*
104+
* @param {Event} event
105+
* @return {boolean}
106+
* @protected
107+
* @override
108+
*/
109+
_shouldCloseOnOutsideClick(event) {
110+
if (this.hasAttribute('is-root') && event.composedPath().includes(this.listenOn)) {
111+
return false;
112+
}
113+
114+
return super._shouldCloseOnOutsideClick(event);
115+
}
64116
}
65117

66118
defineCustomElement(MenuBarSubmenu);
119+
120+
export { MenuBarSubmenu };

packages/menu-bar/test/typings/menu-bar.types.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ import type { ResizeMixinClass } from '@vaadin/component-base/src/resize-mixin.j
77
import type { ItemMixinClass } from '@vaadin/item/src/vaadin-item-mixin.js';
88
import type { ThemableMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
99
import type { ThemePropertyMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-theme-property-mixin.js';
10+
import type { MenuBarButton } from '../../src/vaadin-menu-bar-button.js';
1011
import type { MenuBarItem } from '../../src/vaadin-menu-bar-item.js';
1112
import type { MenuBarListBox } from '../../src/vaadin-menu-bar-list-box.js';
1213
import type { MenuBarI18n, MenuBarMixinClass } from '../../src/vaadin-menu-bar-mixin.js';
14+
import type { MenuBarSubmenu } from '../../src/vaadin-menu-bar-submenu.js';
1315
import type { MenuBar, MenuBarItem as MenuItem, MenuBarItemSelectedEvent } from '../../vaadin-menu-bar.js';
1416

1517
const menu = document.createElement('vaadin-menu-bar');
@@ -76,3 +78,16 @@ assertType<MenuBarListBox>(listBox);
7678
assertType<DirMixinClass>(listBox);
7779
assertType<ListMixinClass>(listBox);
7880
assertType<ThemableMixinClass>(listBox);
81+
82+
// Button
83+
const button = document.createElement('vaadin-menu-bar-button');
84+
85+
assertType<MenuBarButton>(button);
86+
assertType<ThemableMixinClass>(button);
87+
88+
// Submenu
89+
const submenu = document.createElement('vaadin-menu-bar-submenu');
90+
91+
assertType<MenuBarSubmenu>(submenu);
92+
assertType<ThemePropertyMixinClass>(submenu);
93+
assertType<boolean>(submenu.opened);

0 commit comments

Comments
 (0)