@vaadin/menu-bar 23.3.3 → 24.0.0-alpha10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -9
- package/src/vaadin-menu-bar-button.js +9 -1
- package/src/{vaadin-menu-bar-interactions-mixin.d.ts → vaadin-menu-bar-mixin.d.ts} +16 -10
- package/src/{vaadin-menu-bar-interactions-mixin.js → vaadin-menu-bar-mixin.js} +329 -40
- package/src/vaadin-menu-bar-submenu.js +1 -1
- package/src/vaadin-menu-bar.d.ts +11 -9
- package/src/vaadin-menu-bar.js +20 -34
- package/theme/lumo/vaadin-menu-bar-button-styles.js +6 -6
- package/theme/lumo/vaadin-menu-bar-item-styles.js +2 -4
- package/theme/lumo/vaadin-menu-bar-styles.js +3 -3
- package/theme/material/vaadin-menu-bar-button-styles.js +6 -6
- package/theme/material/vaadin-menu-bar-item-styles.js +1 -2
- package/theme/material/vaadin-menu-bar-styles.js +3 -3
- package/web-types.json +31 -9
- package/web-types.lit.json +13 -6
- package/src/vaadin-menu-bar-buttons-mixin.d.ts +0 -21
- package/src/vaadin-menu-bar-buttons-mixin.js +0 -287
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/menu-bar",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "24.0.0-alpha10",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -37,16 +37,16 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@open-wc/dedupe-mixin": "^1.3.0",
|
|
39
39
|
"@polymer/polymer": "^3.0.0",
|
|
40
|
-
"@vaadin/button": "
|
|
41
|
-
"@vaadin/component-base": "
|
|
42
|
-
"@vaadin/context-menu": "
|
|
43
|
-
"@vaadin/vaadin-lumo-styles": "
|
|
44
|
-
"@vaadin/vaadin-material-styles": "
|
|
45
|
-
"@vaadin/vaadin-themable-mixin": "
|
|
40
|
+
"@vaadin/button": "24.0.0-alpha10",
|
|
41
|
+
"@vaadin/component-base": "24.0.0-alpha10",
|
|
42
|
+
"@vaadin/context-menu": "24.0.0-alpha10",
|
|
43
|
+
"@vaadin/vaadin-lumo-styles": "24.0.0-alpha10",
|
|
44
|
+
"@vaadin/vaadin-material-styles": "24.0.0-alpha10",
|
|
45
|
+
"@vaadin/vaadin-themable-mixin": "24.0.0-alpha10"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@esm-bundle/chai": "^4.3.4",
|
|
49
|
-
"@vaadin/icon": "
|
|
49
|
+
"@vaadin/icon": "24.0.0-alpha10",
|
|
50
50
|
"@vaadin/testing-helpers": "^0.3.2",
|
|
51
51
|
"sinon": "^13.0.2"
|
|
52
52
|
},
|
|
@@ -54,5 +54,5 @@
|
|
|
54
54
|
"web-types.json",
|
|
55
55
|
"web-types.lit.json"
|
|
56
56
|
],
|
|
57
|
-
"gitHead": "
|
|
57
|
+
"gitHead": "2e04534d8b47bcd216f89b5f849bafef1a73b174"
|
|
58
58
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
|
-
* Copyright (c) 2019 -
|
|
3
|
+
* Copyright (c) 2019 - 2023 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
6
|
import { Button } from '@vaadin/button/src/vaadin-button.js';
|
|
@@ -9,6 +9,14 @@ import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themab
|
|
|
9
9
|
registerStyles(
|
|
10
10
|
'vaadin-menu-bar-button',
|
|
11
11
|
css`
|
|
12
|
+
:host {
|
|
13
|
+
flex-shrink: 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
:host([slot='overflow']) {
|
|
17
|
+
margin-inline-end: 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
12
20
|
[part='label'] ::slotted(vaadin-context-menu-item) {
|
|
13
21
|
position: relative;
|
|
14
22
|
z-index: 1;
|
|
@@ -1,31 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
|
-
* Copyright (c) 2019 -
|
|
3
|
+
* Copyright (c) 2019 - 2023 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
6
|
import type { Constructor } from '@open-wc/dedupe-mixin';
|
|
7
|
+
import type { ControllerMixinClass } from '@vaadin/component-base/src/controller-mixin.js';
|
|
7
8
|
import type { FocusMixinClass } from '@vaadin/component-base/src/focus-mixin.js';
|
|
8
9
|
import type { KeyboardDirectionMixinClass } from '@vaadin/component-base/src/keyboard-direction-mixin.js';
|
|
9
10
|
import type { KeyboardMixinClass } from '@vaadin/component-base/src/keyboard-mixin.js';
|
|
11
|
+
import type { ResizeMixinClass } from '@vaadin/component-base/src/resize-mixin.js';
|
|
10
12
|
|
|
11
|
-
export declare function
|
|
13
|
+
export declare function MenuBarMixin<T extends Constructor<HTMLElement>>(
|
|
12
14
|
base: T,
|
|
13
|
-
): Constructor<
|
|
14
|
-
Constructor<
|
|
15
|
+
): Constructor<ControllerMixinClass> &
|
|
16
|
+
Constructor<FocusMixinClass> &
|
|
15
17
|
Constructor<KeyboardDirectionMixinClass> &
|
|
16
18
|
Constructor<KeyboardMixinClass> &
|
|
19
|
+
Constructor<MenuBarMixinClass> &
|
|
20
|
+
Constructor<ResizeMixinClass> &
|
|
17
21
|
T;
|
|
18
22
|
|
|
19
|
-
export declare class
|
|
23
|
+
export declare class MenuBarMixinClass {
|
|
20
24
|
/**
|
|
21
25
|
* If true, the submenu will open on hover (mouseover) instead of click.
|
|
22
26
|
* @attr {boolean} open-on-hover
|
|
23
27
|
*/
|
|
24
28
|
openOnHover: boolean | null | undefined;
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
protected readonly _buttons: HTMLElement[];
|
|
31
|
+
|
|
32
|
+
protected readonly _container: HTMLElement;
|
|
33
|
+
|
|
34
|
+
protected readonly _overflow: HTMLElement;
|
|
35
|
+
|
|
36
|
+
protected _hasOverflow: boolean;
|
|
31
37
|
}
|
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
|
-
* Copyright (c) 2019 -
|
|
3
|
+
* Copyright (c) 2019 - 2023 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
+
import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
|
|
6
7
|
import { FocusMixin } from '@vaadin/component-base/src/focus-mixin.js';
|
|
7
|
-
import { isKeyboardActive } from '@vaadin/component-base/src/focus-utils.js';
|
|
8
|
+
import { isElementFocused, isKeyboardActive } from '@vaadin/component-base/src/focus-utils.js';
|
|
8
9
|
import { KeyboardDirectionMixin } from '@vaadin/component-base/src/keyboard-direction-mixin.js';
|
|
10
|
+
import { ResizeMixin } from '@vaadin/component-base/src/resize-mixin.js';
|
|
11
|
+
import { SlotController } from '@vaadin/component-base/src/slot-controller.js';
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* @polymerMixin
|
|
15
|
+
* @mixes ControllerMixin
|
|
12
16
|
* @mixes FocusMixin
|
|
13
|
-
* @mixes
|
|
17
|
+
* @mixes KeyboardDirectionMixin
|
|
18
|
+
* @mixes ResizeMixin
|
|
14
19
|
*/
|
|
15
|
-
export const
|
|
16
|
-
class
|
|
20
|
+
export const MenuBarMixin = (superClass) =>
|
|
21
|
+
class MenuBarMixinClass extends KeyboardDirectionMixin(ResizeMixin(FocusMixin(ControllerMixin(superClass)))) {
|
|
17
22
|
static get properties() {
|
|
18
23
|
return {
|
|
19
24
|
/**
|
|
@@ -23,22 +28,110 @@ export const InteractionsMixin = (superClass) =>
|
|
|
23
28
|
openOnHover: {
|
|
24
29
|
type: Boolean,
|
|
25
30
|
},
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @type {boolean}
|
|
34
|
+
* @protected
|
|
35
|
+
*/
|
|
36
|
+
_hasOverflow: {
|
|
37
|
+
type: Boolean,
|
|
38
|
+
value: false,
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
/** @protected */
|
|
42
|
+
_overflow: {
|
|
43
|
+
type: Object,
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
/** @protected */
|
|
47
|
+
_container: {
|
|
48
|
+
type: Object,
|
|
49
|
+
},
|
|
26
50
|
};
|
|
27
51
|
}
|
|
28
52
|
|
|
53
|
+
static get observers() {
|
|
54
|
+
return [
|
|
55
|
+
'_itemsChanged(items, items.splices)',
|
|
56
|
+
'__hasOverflowChanged(_hasOverflow, _overflow)',
|
|
57
|
+
'__i18nChanged(i18n, _overflow)',
|
|
58
|
+
'_menuItemsChanged(items, _overflow, _container, items.splices)',
|
|
59
|
+
];
|
|
60
|
+
}
|
|
61
|
+
|
|
29
62
|
constructor() {
|
|
30
63
|
super();
|
|
31
64
|
this.__boundOnContextMenuKeydown = this.__onContextMenuKeydown.bind(this);
|
|
32
65
|
}
|
|
33
66
|
|
|
34
|
-
|
|
35
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Override getter from `KeyboardDirectionMixin`
|
|
69
|
+
* to use expanded button for arrow navigation
|
|
70
|
+
* when the sub-menu is opened and has focus.
|
|
71
|
+
*
|
|
72
|
+
* @return {Element | null}
|
|
73
|
+
* @protected
|
|
74
|
+
* @override
|
|
75
|
+
*/
|
|
76
|
+
get focused() {
|
|
77
|
+
return (this._getItems() || []).find(isElementFocused) || this._expandedButton;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Override getter from `KeyboardDirectionMixin`.
|
|
82
|
+
*
|
|
83
|
+
* @return {boolean}
|
|
84
|
+
* @protected
|
|
85
|
+
* @override
|
|
86
|
+
*/
|
|
87
|
+
get _vertical() {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Override getter from `ResizeMixin` to observe parent.
|
|
93
|
+
*
|
|
94
|
+
* @protected
|
|
95
|
+
* @override
|
|
96
|
+
*/
|
|
97
|
+
get _observeParent() {
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @return {!Array<!HTMLElement>}
|
|
103
|
+
* @protected
|
|
104
|
+
*/
|
|
105
|
+
get _buttons() {
|
|
106
|
+
return Array.from(this.querySelectorAll('vaadin-menu-bar-button'));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** @private */
|
|
110
|
+
get _subMenu() {
|
|
111
|
+
return this.shadowRoot.querySelector('vaadin-menu-bar-submenu');
|
|
36
112
|
}
|
|
37
113
|
|
|
38
114
|
/** @protected */
|
|
39
115
|
ready() {
|
|
40
116
|
super.ready();
|
|
41
117
|
|
|
118
|
+
this.setAttribute('role', 'menubar');
|
|
119
|
+
|
|
120
|
+
this._overflowController = new SlotController(this, 'overflow', 'vaadin-menu-bar-button', {
|
|
121
|
+
initializer: (btn) => {
|
|
122
|
+
btn.setAttribute('hidden', '');
|
|
123
|
+
|
|
124
|
+
const dots = document.createElement('div');
|
|
125
|
+
dots.setAttribute('aria-hidden', 'true');
|
|
126
|
+
dots.textContent = '···';
|
|
127
|
+
btn.appendChild(dots);
|
|
128
|
+
|
|
129
|
+
this._overflow = btn;
|
|
130
|
+
this._initButtonAttrs(btn);
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
this.addController(this._overflowController);
|
|
134
|
+
|
|
42
135
|
this.addEventListener('mousedown', () => this._hideTooltip());
|
|
43
136
|
this.addEventListener('mouseleave', () => this._hideTooltip());
|
|
44
137
|
|
|
@@ -48,56 +141,257 @@ export const InteractionsMixin = (superClass) =>
|
|
|
48
141
|
const overlay = this._subMenu.$.overlay;
|
|
49
142
|
overlay.addEventListener('keydown', this.__boundOnContextMenuKeydown);
|
|
50
143
|
|
|
51
|
-
const container = this.
|
|
144
|
+
const container = this.shadowRoot.querySelector('[part="container"]');
|
|
52
145
|
container.addEventListener('click', this.__onButtonClick.bind(this));
|
|
53
146
|
container.addEventListener('mouseover', (e) => this._onMouseOver(e));
|
|
147
|
+
|
|
148
|
+
this._container = container;
|
|
54
149
|
}
|
|
55
150
|
|
|
56
151
|
/**
|
|
57
|
-
* Override
|
|
58
|
-
* to
|
|
59
|
-
* use the expanded button as a fallback.
|
|
152
|
+
* Override method inherited from `KeyboardDirectionMixin`
|
|
153
|
+
* to use the list of menu-bar buttons as items.
|
|
60
154
|
*
|
|
61
|
-
* @return {Element
|
|
155
|
+
* @return {Element[]}
|
|
62
156
|
* @protected
|
|
63
157
|
* @override
|
|
64
158
|
*/
|
|
65
|
-
|
|
66
|
-
return this.
|
|
159
|
+
_getItems() {
|
|
160
|
+
return this._buttons;
|
|
67
161
|
}
|
|
68
162
|
|
|
69
|
-
/**
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
* @protected
|
|
74
|
-
* @override
|
|
75
|
-
*/
|
|
76
|
-
get _vertical() {
|
|
77
|
-
return false;
|
|
163
|
+
/** @protected */
|
|
164
|
+
disconnectedCallback() {
|
|
165
|
+
super.disconnectedCallback();
|
|
166
|
+
this._hideTooltip(true);
|
|
78
167
|
}
|
|
79
168
|
|
|
80
169
|
/**
|
|
81
|
-
*
|
|
82
|
-
*
|
|
170
|
+
* Implement callback from `ResizeMixin` to update buttons
|
|
171
|
+
* and detect whether to show or hide the overflow button.
|
|
83
172
|
*
|
|
84
|
-
* @return {Element[]}
|
|
85
173
|
* @protected
|
|
86
174
|
* @override
|
|
87
175
|
*/
|
|
88
|
-
|
|
89
|
-
|
|
176
|
+
_onResize() {
|
|
177
|
+
this.__detectOverflow();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** @private */
|
|
181
|
+
__hasOverflowChanged(hasOverflow, overflow) {
|
|
182
|
+
if (overflow) {
|
|
183
|
+
overflow.toggleAttribute('hidden', !hasOverflow);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** @private */
|
|
188
|
+
_menuItemsChanged(items, overflow, container) {
|
|
189
|
+
if (!overflow || !container) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (items !== this._oldItems) {
|
|
194
|
+
this._oldItems = items;
|
|
195
|
+
this.__renderButtons(items);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** @private */
|
|
200
|
+
__i18nChanged(i18n, overflow) {
|
|
201
|
+
if (overflow && i18n && i18n.moreOptions !== undefined) {
|
|
202
|
+
if (i18n.moreOptions) {
|
|
203
|
+
overflow.setAttribute('aria-label', i18n.moreOptions);
|
|
204
|
+
} else {
|
|
205
|
+
overflow.removeAttribute('aria-label');
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** @private */
|
|
211
|
+
__getOverflowCount(overflow) {
|
|
212
|
+
// We can't use optional chaining due to webpack 4
|
|
213
|
+
return (overflow.item && overflow.item.children && overflow.item.children.length) || 0;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** @private */
|
|
217
|
+
__restoreButtons(buttons) {
|
|
218
|
+
for (let i = 0; i < buttons.length; i++) {
|
|
219
|
+
const btn = buttons[i];
|
|
220
|
+
btn.disabled = (btn.item && btn.item.disabled) || this.disabled;
|
|
221
|
+
btn.style.visibility = '';
|
|
222
|
+
btn.style.position = '';
|
|
223
|
+
|
|
224
|
+
// Teleport item component back from "overflow" sub-menu
|
|
225
|
+
const item = btn.item && btn.item.component;
|
|
226
|
+
if (item instanceof HTMLElement && item.getAttribute('role') === 'menuitem') {
|
|
227
|
+
btn.appendChild(item);
|
|
228
|
+
item.removeAttribute('role');
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
this.__updateOverflow([]);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/** @private */
|
|
235
|
+
__updateOverflow(items) {
|
|
236
|
+
this._overflow.item = { children: items };
|
|
237
|
+
this._hasOverflow = items.length > 0;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/** @private */
|
|
241
|
+
__setOverflowItems(buttons, overflow) {
|
|
242
|
+
const container = this._container;
|
|
243
|
+
|
|
244
|
+
if (container.offsetWidth < container.scrollWidth) {
|
|
245
|
+
this._hasOverflow = true;
|
|
246
|
+
|
|
247
|
+
const isRTL = this.__isRTL;
|
|
248
|
+
|
|
249
|
+
let i;
|
|
250
|
+
for (i = buttons.length; i > 0; i--) {
|
|
251
|
+
const btn = buttons[i - 1];
|
|
252
|
+
const btnStyle = getComputedStyle(btn);
|
|
253
|
+
|
|
254
|
+
// If this button isn't overflowing, then the rest aren't either
|
|
255
|
+
if (
|
|
256
|
+
(!isRTL && btn.offsetLeft + btn.offsetWidth < container.offsetWidth - overflow.offsetWidth) ||
|
|
257
|
+
(isRTL && btn.offsetLeft >= overflow.offsetWidth)
|
|
258
|
+
) {
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
btn.disabled = true;
|
|
263
|
+
btn.style.visibility = 'hidden';
|
|
264
|
+
btn.style.position = 'absolute';
|
|
265
|
+
// Save width for buttons with component
|
|
266
|
+
btn.style.width = btnStyle.width;
|
|
267
|
+
}
|
|
268
|
+
const items = buttons.filter((_, idx) => idx >= i).map((b) => b.item);
|
|
269
|
+
this.__updateOverflow(items);
|
|
270
|
+
}
|
|
90
271
|
}
|
|
91
272
|
|
|
92
273
|
/** @private */
|
|
93
|
-
|
|
94
|
-
|
|
274
|
+
__detectOverflow() {
|
|
275
|
+
const overflow = this._overflow;
|
|
276
|
+
const buttons = this._buttons.filter((btn) => btn !== overflow);
|
|
277
|
+
const oldOverflowCount = this.__getOverflowCount(overflow);
|
|
278
|
+
|
|
279
|
+
// Reset all buttons in the menu bar and the overflow button
|
|
280
|
+
this.__restoreButtons(buttons);
|
|
281
|
+
|
|
282
|
+
// Hide any overflowing buttons and put them in the 'overflow' button
|
|
283
|
+
this.__setOverflowItems(buttons, overflow);
|
|
284
|
+
|
|
285
|
+
const newOverflowCount = this.__getOverflowCount(overflow);
|
|
286
|
+
if (oldOverflowCount !== newOverflowCount && this._subMenu.opened) {
|
|
287
|
+
this._subMenu.close();
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const isSingleButton = newOverflowCount === buttons.length || (newOverflowCount === 0 && buttons.length === 1);
|
|
291
|
+
this.toggleAttribute('has-single-button', isSingleButton);
|
|
95
292
|
}
|
|
96
293
|
|
|
97
294
|
/** @protected */
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
295
|
+
_removeButtons() {
|
|
296
|
+
this._buttons.forEach((button) => {
|
|
297
|
+
if (button !== this._overflow) {
|
|
298
|
+
this.removeChild(button);
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/** @protected */
|
|
304
|
+
_initButton(item) {
|
|
305
|
+
const button = document.createElement('vaadin-menu-bar-button');
|
|
306
|
+
|
|
307
|
+
const itemCopy = { ...item };
|
|
308
|
+
button.item = itemCopy;
|
|
309
|
+
|
|
310
|
+
if (item.component) {
|
|
311
|
+
const component = this.__getComponent(itemCopy);
|
|
312
|
+
itemCopy.component = component;
|
|
313
|
+
// Save item for overflow menu
|
|
314
|
+
component.item = itemCopy;
|
|
315
|
+
button.appendChild(component);
|
|
316
|
+
} else if (item.text) {
|
|
317
|
+
button.textContent = item.text;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return button;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/** @protected */
|
|
324
|
+
_initButtonAttrs(button) {
|
|
325
|
+
button.setAttribute('role', 'menuitem');
|
|
326
|
+
|
|
327
|
+
if (button === this._overflow || (button.item && button.item.children)) {
|
|
328
|
+
button.setAttribute('aria-haspopup', 'true');
|
|
329
|
+
button.setAttribute('aria-expanded', 'false');
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/** @protected */
|
|
334
|
+
_setButtonDisabled(button, disabled) {
|
|
335
|
+
button.disabled = disabled;
|
|
336
|
+
button.setAttribute('tabindex', disabled ? '-1' : '0');
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/** @protected */
|
|
340
|
+
_setButtonTheme(btn, hostTheme) {
|
|
341
|
+
let theme = hostTheme;
|
|
342
|
+
|
|
343
|
+
// Item theme takes precedence over host theme even if it's empty, as long as it's not undefined or null
|
|
344
|
+
const itemTheme = btn.item && btn.item.theme;
|
|
345
|
+
if (itemTheme != null) {
|
|
346
|
+
theme = Array.isArray(itemTheme) ? itemTheme.join(' ') : itemTheme;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (theme) {
|
|
350
|
+
btn.setAttribute('theme', theme);
|
|
351
|
+
} else {
|
|
352
|
+
btn.removeAttribute('theme');
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/** @private */
|
|
357
|
+
__getComponent(item) {
|
|
358
|
+
const itemComponent = item.component;
|
|
359
|
+
let component;
|
|
360
|
+
|
|
361
|
+
const isElement = itemComponent instanceof HTMLElement;
|
|
362
|
+
// Use existing item component, if any
|
|
363
|
+
if (isElement && itemComponent.localName === 'vaadin-context-menu-item') {
|
|
364
|
+
component = itemComponent;
|
|
365
|
+
} else {
|
|
366
|
+
component = document.createElement('vaadin-context-menu-item');
|
|
367
|
+
component.appendChild(isElement ? itemComponent : document.createElement(itemComponent));
|
|
368
|
+
}
|
|
369
|
+
if (item.text) {
|
|
370
|
+
const node = component.firstChild || component;
|
|
371
|
+
node.textContent = item.text;
|
|
372
|
+
}
|
|
373
|
+
component.setAttribute('theme', 'menu-bar-item');
|
|
374
|
+
return component;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/** @private */
|
|
378
|
+
__renderButtons(items = []) {
|
|
379
|
+
this._removeButtons();
|
|
380
|
+
|
|
381
|
+
/* Empty array, do nothing */
|
|
382
|
+
if (items.length === 0) {
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
items.forEach((item) => {
|
|
387
|
+
const button = this._initButton(item);
|
|
388
|
+
this.insertBefore(button, this._overflow);
|
|
389
|
+
this._setButtonDisabled(button, item.disabled);
|
|
390
|
+
this._initButtonAttrs(button);
|
|
391
|
+
this._setButtonTheme(button, this._theme);
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
this.__detectOverflow();
|
|
101
395
|
}
|
|
102
396
|
|
|
103
397
|
/**
|
|
@@ -129,7 +423,7 @@ export const InteractionsMixin = (superClass) =>
|
|
|
129
423
|
|
|
130
424
|
/** @protected */
|
|
131
425
|
_hideTooltip(immediate) {
|
|
132
|
-
const tooltip = this._tooltipController.node;
|
|
426
|
+
const tooltip = this._tooltipController && this._tooltipController.node;
|
|
133
427
|
if (tooltip) {
|
|
134
428
|
tooltip._stateController.close(immediate);
|
|
135
429
|
}
|
|
@@ -192,7 +486,7 @@ export const InteractionsMixin = (superClass) =>
|
|
|
192
486
|
*/
|
|
193
487
|
_setFocused(focused) {
|
|
194
488
|
if (focused) {
|
|
195
|
-
const target = this.
|
|
489
|
+
const target = this.querySelector('[tabindex="0"]');
|
|
196
490
|
if (target) {
|
|
197
491
|
this._buttons.forEach((btn) => {
|
|
198
492
|
this._setTabindex(btn, btn === target);
|
|
@@ -278,11 +572,6 @@ export const InteractionsMixin = (superClass) =>
|
|
|
278
572
|
}
|
|
279
573
|
}
|
|
280
574
|
|
|
281
|
-
/** @private */
|
|
282
|
-
get _subMenu() {
|
|
283
|
-
return this.shadowRoot.querySelector('vaadin-menu-bar-submenu');
|
|
284
|
-
}
|
|
285
|
-
|
|
286
575
|
/** @private */
|
|
287
576
|
_itemsChanged() {
|
|
288
577
|
const subMenu = this._subMenu;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
|
-
* Copyright (c) 2019 -
|
|
3
|
+
* Copyright (c) 2019 - 2023 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
6
|
import { ContextMenu } from '@vaadin/context-menu/src/vaadin-context-menu.js';
|
package/src/vaadin-menu-bar.d.ts
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
|
-
* Copyright (c) 2019 -
|
|
3
|
+
* Copyright (c) 2019 - 2023 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
-
import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
|
|
7
6
|
import { DisabledMixin } from '@vaadin/component-base/src/disabled-mixin.js';
|
|
8
7
|
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
|
|
9
8
|
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
10
|
-
import {
|
|
11
|
-
import { InteractionsMixin } from './vaadin-menu-bar-interactions-mixin.js';
|
|
9
|
+
import { MenuBarMixin } from './vaadin-menu-bar-mixin.js';
|
|
12
10
|
|
|
13
11
|
export interface MenuBarItem {
|
|
14
12
|
/**
|
|
@@ -87,8 +85,6 @@ export interface MenuBarEventMap extends HTMLElementEventMap, MenuBarCustomEvent
|
|
|
87
85
|
* Part name | Description
|
|
88
86
|
* ------------------|----------------
|
|
89
87
|
* `container` | The container wrapping menu bar buttons.
|
|
90
|
-
* `menu-bar-button` | The menu bar button.
|
|
91
|
-
* `overflow-button` | The "overflow" button appearing when menu bar width is not enough to fit all the buttons.
|
|
92
88
|
*
|
|
93
89
|
* The following state attributes are available for styling:
|
|
94
90
|
*
|
|
@@ -111,9 +107,7 @@ export interface MenuBarEventMap extends HTMLElementEventMap, MenuBarCustomEvent
|
|
|
111
107
|
*
|
|
112
108
|
* @fires {CustomEvent} item-selected - Fired when a submenu item or menu bar button without children is clicked.
|
|
113
109
|
*/
|
|
114
|
-
declare class MenuBar extends
|
|
115
|
-
DisabledMixin(InteractionsMixin(ElementMixin(ThemableMixin(ControllerMixin(HTMLElement))))),
|
|
116
|
-
) {
|
|
110
|
+
declare class MenuBar extends MenuBarMixin(DisabledMixin(ElementMixin(ThemableMixin(HTMLElement)))) {
|
|
117
111
|
/**
|
|
118
112
|
* Defines a hierarchical structure, where root level items represent menu bar buttons,
|
|
119
113
|
* and `children` property configures a submenu with items to be opened below
|
|
@@ -166,6 +160,14 @@ declare class MenuBar extends ButtonsMixin(
|
|
|
166
160
|
*/
|
|
167
161
|
i18n: MenuBarI18n;
|
|
168
162
|
|
|
163
|
+
/**
|
|
164
|
+
* A space-delimited list of CSS class names
|
|
165
|
+
* to set on each sub-menu overlay element.
|
|
166
|
+
*
|
|
167
|
+
* @attr {string} overlay-class
|
|
168
|
+
*/
|
|
169
|
+
overlayClass: string;
|
|
170
|
+
|
|
169
171
|
addEventListener<K extends keyof MenuBarEventMap>(
|
|
170
172
|
type: K,
|
|
171
173
|
listener: (this: MenuBar, ev: MenuBarEventMap[K]) => void,
|