Skip to content

Commit 2945dbc

Browse files
authoredFeb 20, 2025
feat: allow adding custom data to menu bar item types (#8698)
* feat: allow adding custom data to menu bar item types * add missing type parameters
1 parent 3b5970d commit 2945dbc

File tree

3 files changed

+56
-24
lines changed

3 files changed

+56
-24
lines changed
 

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

+18-10
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import type { KeyboardMixinClass } from '@vaadin/a11y-base/src/keyboard-mixin.js
1111
import type { ControllerMixinClass } from '@vaadin/component-base/src/controller-mixin.js';
1212
import type { ResizeMixinClass } from '@vaadin/component-base/src/resize-mixin.js';
1313

14-
export interface MenuBarItem {
14+
export type MenuBarItem<TItemData extends object = object> = {
1515
/**
1616
* Text to be set as the menu button component's textContent.
1717
*/
@@ -37,40 +37,40 @@ export interface MenuBarItem {
3737
/**
3838
* Array of submenu items.
3939
*/
40-
children?: SubMenuItem[];
40+
children?: Array<SubMenuItem<TItemData>>;
4141

4242
/**
4343
* Class/classes to be set to the class attribute of the button.
4444
*/
4545
className?: string;
46-
}
46+
} & TItemData;
4747

48-
export interface SubMenuItem {
48+
export type SubMenuItem<TItemData extends object = object> = {
4949
text?: string;
5050
component?: HTMLElement | string;
5151
disabled?: boolean;
5252
theme?: string[] | string;
5353
checked?: boolean;
5454
className?: string;
55-
children?: SubMenuItem[];
56-
}
55+
children?: Array<SubMenuItem<TItemData>>;
56+
} & TItemData;
5757

5858
export interface MenuBarI18n {
5959
moreOptions: string;
6060
}
6161

62-
export declare function MenuBarMixin<T extends Constructor<HTMLElement>>(
62+
export declare function MenuBarMixin<T extends Constructor<HTMLElement>, TItem extends MenuBarItem = MenuBarItem>(
6363
base: T,
6464
): Constructor<ControllerMixinClass> &
6565
Constructor<DisabledMixinClass> &
6666
Constructor<FocusMixinClass> &
6767
Constructor<KeyboardDirectionMixinClass> &
6868
Constructor<KeyboardMixinClass> &
69-
Constructor<MenuBarMixinClass> &
69+
Constructor<MenuBarMixinClass<TItem>> &
7070
Constructor<ResizeMixinClass> &
7171
T;
7272

73-
export declare class MenuBarMixinClass {
73+
export declare class MenuBarMixinClass<TItem extends MenuBarItem = MenuBarItem> {
7474
/**
7575
* Defines a hierarchical structure, where root level items represent menu bar buttons,
7676
* and `children` property configures a submenu with items to be opened below
@@ -118,7 +118,7 @@ export declare class MenuBarMixinClass {
118118
* window.Vaadin.featureFlags.accessibleDisabledButtons = true;
119119
* ```
120120
*/
121-
items: MenuBarItem[];
121+
items: TItem[];
122122

123123
/**
124124
* The object used to localize this component.
@@ -183,3 +183,11 @@ export declare class MenuBarMixinClass {
183183

184184
protected _hasOverflow: boolean;
185185
}
186+
187+
export declare interface MenuBarMixinClass
188+
extends ControllerMixinClass,
189+
DisabledMixinClass,
190+
FocusMixinClass,
191+
KeyboardDirectionMixinClass,
192+
KeyboardMixinClass,
193+
ResizeMixinClass {}

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

+21-13
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,25 @@
33
* Copyright (c) 2019 - 2025 Vaadin Ltd.
44
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
55
*/
6-
import { DisabledMixin } from '@vaadin/a11y-base/src/disabled-mixin.js';
7-
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
8-
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
9-
import { type MenuBarItem, MenuBarMixin } from './vaadin-menu-bar-mixin.js';
6+
import type { DisabledMixinClass } from '@vaadin/a11y-base/src/disabled-mixin.js';
7+
import type { ElementMixinClass } from '@vaadin/component-base/src/element-mixin.js';
8+
import type { ThemableMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
9+
import type { MenuBarItem, MenuBarMixinClass } from './vaadin-menu-bar-mixin.js';
1010

1111
export { MenuBarItem, MenuBarI18n, SubMenuItem } from './vaadin-menu-bar-mixin.js';
1212

1313
/**
1414
* Fired when a submenu item or menu bar button without children is clicked.
1515
*/
16-
export type MenuBarItemSelectedEvent = CustomEvent<{ value: MenuBarItem }>;
16+
export type MenuBarItemSelectedEvent<TItem extends MenuBarItem = MenuBarItem> = CustomEvent<{ value: TItem }>;
1717

18-
export interface MenuBarCustomEventMap {
19-
'item-selected': MenuBarItemSelectedEvent;
18+
export interface MenuBarCustomEventMap<TItem extends MenuBarItem = MenuBarItem> {
19+
'item-selected': MenuBarItemSelectedEvent<TItem>;
2020
}
2121

22-
export interface MenuBarEventMap extends HTMLElementEventMap, MenuBarCustomEventMap {}
22+
export interface MenuBarEventMap<TItem extends MenuBarItem = MenuBarItem>
23+
extends HTMLElementEventMap,
24+
MenuBarCustomEventMap<TItem> {}
2325

2426
/**
2527
* `<vaadin-menu-bar>` is a Web Component providing a set of horizontally stacked buttons offering
@@ -77,20 +79,26 @@ export interface MenuBarEventMap extends HTMLElementEventMap, MenuBarCustomEvent
7779
*
7880
* @fires {CustomEvent} item-selected - Fired when a submenu item or menu bar button without children is clicked.
7981
*/
80-
declare class MenuBar extends MenuBarMixin(DisabledMixin(ElementMixin(ThemableMixin(HTMLElement)))) {
81-
addEventListener<K extends keyof MenuBarEventMap>(
82+
declare class MenuBar<TItem extends MenuBarItem = MenuBarItem> extends HTMLElement {
83+
addEventListener<K extends keyof MenuBarEventMap<TItem>>(
8284
type: K,
83-
listener: (this: MenuBar, ev: MenuBarEventMap[K]) => void,
85+
listener: (this: MenuBar<TItem>, ev: MenuBarEventMap<TItem>[K]) => void,
8486
options?: AddEventListenerOptions | boolean,
8587
): void;
8688

87-
removeEventListener<K extends keyof MenuBarEventMap>(
89+
removeEventListener<K extends keyof MenuBarEventMap<TItem>>(
8890
type: K,
89-
listener: (this: MenuBar, ev: MenuBarEventMap[K]) => void,
91+
listener: (this: MenuBar<TItem>, ev: MenuBarEventMap<TItem>[K]) => void,
9092
options?: EventListenerOptions | boolean,
9193
): void;
9294
}
9395

96+
interface MenuBar<TItem extends MenuBarItem = MenuBarItem>
97+
extends MenuBarMixinClass<TItem>,
98+
DisabledMixinClass,
99+
ElementMixinClass,
100+
ThemableMixinClass {}
101+
94102
declare global {
95103
interface HTMLElementTagNameMap {
96104
'vaadin-menu-bar': MenuBar;

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

+17-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import type { ThemableMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-th
99
import type { MenuBarItem } from '../../src/vaadin-menu-bar-item.js';
1010
import type { MenuBarListBox } from '../../src/vaadin-menu-bar-list-box.js';
1111
import type { MenuBarMixinClass } from '../../src/vaadin-menu-bar-mixin.js';
12-
import type { MenuBarItem as MenuItem, MenuBarItemSelectedEvent } from '../../vaadin-menu-bar.js';
12+
import type { MenuBar, MenuBarItem as MenuItem, MenuBarItemSelectedEvent } from '../../vaadin-menu-bar.js';
1313

1414
const menu = document.createElement('vaadin-menu-bar');
1515

@@ -39,6 +39,22 @@ assertType<string[] | string | undefined>(menuItem.theme);
3939
assertType<MenuItem[] | undefined>(menuItem.children);
4040
assertType<HTMLElement | string | undefined>(menuItem.component);
4141

42+
// Custom item data
43+
interface ItemData {
44+
type: 'copy' | 'cut' | 'paste';
45+
value: string;
46+
}
47+
48+
const narrowedMenu = menu as MenuBar<MenuItem<ItemData>>;
49+
50+
assertType<ItemData>(narrowedMenu.items[0]);
51+
assertType<ItemData>(narrowedMenu.items[0].children![0]);
52+
assertType<ItemData>(narrowedMenu.items[0].children![0].children![0]);
53+
54+
narrowedMenu.addEventListener('item-selected', (event) => {
55+
assertType<ItemData>(event.detail.value);
56+
});
57+
4258
// Item
4359
const item = document.createElement('vaadin-menu-bar-item');
4460

0 commit comments

Comments
 (0)