@vaadin/menu-bar 25.0.0-alpha2 → 25.0.0-alpha20
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 +15 -16
- package/src/styles/vaadin-menu-bar-base-styles.d.ts +8 -0
- package/src/styles/vaadin-menu-bar-base-styles.js +56 -0
- package/src/styles/vaadin-menu-bar-button-base-styles.d.ts +8 -0
- package/src/styles/vaadin-menu-bar-button-base-styles.js +47 -0
- package/src/styles/vaadin-menu-bar-item-base-styles.d.ts +8 -0
- package/src/styles/vaadin-menu-bar-item-base-styles.js +8 -0
- package/src/styles/vaadin-menu-bar-overlay-base-styles.d.ts +8 -0
- package/src/styles/vaadin-menu-bar-overlay-base-styles.js +9 -0
- package/src/vaadin-menu-bar-button.d.ts +19 -0
- package/src/vaadin-menu-bar-button.js +4 -13
- package/src/vaadin-menu-bar-item.js +5 -11
- package/src/vaadin-menu-bar-list-box.js +5 -18
- package/src/vaadin-menu-bar-mixin.d.ts +5 -12
- package/src/vaadin-menu-bar-mixin.js +155 -156
- package/src/vaadin-menu-bar-overlay.js +7 -4
- package/src/vaadin-menu-bar-submenu.d.ts +20 -0
- package/src/vaadin-menu-bar-submenu.js +83 -8
- package/src/vaadin-menu-bar.d.ts +3 -6
- package/src/vaadin-menu-bar.js +11 -27
- package/vaadin-menu-bar.js +1 -1
- package/web-types.json +4 -26
- package/web-types.lit.json +4 -11
- package/src/vaadin-menu-bar-submenu-mixin.js +0 -66
- package/theme/lumo/vaadin-menu-bar-button-styles.d.ts +0 -1
- package/theme/lumo/vaadin-menu-bar-button-styles.js +0 -128
- package/theme/lumo/vaadin-menu-bar-button.d.ts +0 -2
- package/theme/lumo/vaadin-menu-bar-button.js +0 -2
- package/theme/lumo/vaadin-menu-bar-item-styles.d.ts +0 -2
- package/theme/lumo/vaadin-menu-bar-item-styles.js +0 -27
- package/theme/lumo/vaadin-menu-bar-list-box-styles.d.ts +0 -1
- package/theme/lumo/vaadin-menu-bar-list-box-styles.js +0 -5
- package/theme/lumo/vaadin-menu-bar-overlay-styles.d.ts +0 -1
- package/theme/lumo/vaadin-menu-bar-overlay-styles.js +0 -13
- package/theme/lumo/vaadin-menu-bar-styles.d.ts +0 -1
- package/theme/lumo/vaadin-menu-bar-styles.js +0 -17
- package/theme/lumo/vaadin-menu-bar.d.ts +0 -6
- package/theme/lumo/vaadin-menu-bar.js +0 -6
|
@@ -10,6 +10,8 @@ import { DisabledMixin } from '@vaadin/a11y-base/src/disabled-mixin.js';
|
|
|
10
10
|
import { FocusMixin } from '@vaadin/a11y-base/src/focus-mixin.js';
|
|
11
11
|
import { isElementFocused, isKeyboardActive } from '@vaadin/a11y-base/src/focus-utils.js';
|
|
12
12
|
import { KeyboardDirectionMixin } from '@vaadin/a11y-base/src/keyboard-direction-mixin.js';
|
|
13
|
+
import { microTask } from '@vaadin/component-base/src/async.js';
|
|
14
|
+
import { Debouncer } from '@vaadin/component-base/src/debounce.js';
|
|
13
15
|
import { I18nMixin } from '@vaadin/component-base/src/i18n-mixin.js';
|
|
14
16
|
import { ResizeMixin } from '@vaadin/component-base/src/resize-mixin.js';
|
|
15
17
|
import { SlotController } from '@vaadin/component-base/src/slot-controller.js';
|
|
@@ -74,10 +76,10 @@ export const MenuBarMixin = (superClass) =>
|
|
|
74
76
|
* @property {string} text - Text to be set as the menu button component's textContent.
|
|
75
77
|
* @property {string} tooltip - Text to be set as the menu button's tooltip.
|
|
76
78
|
* Requires a `<vaadin-tooltip slot="tooltip">` element to be added inside the `<vaadin-menu-bar>`.
|
|
77
|
-
* @property {
|
|
79
|
+
* @property {string | HTMLElement} component - The component to represent the button content.
|
|
78
80
|
* Either a tagName or an element instance. Defaults to "vaadin-menu-bar-item".
|
|
79
81
|
* @property {boolean} disabled - If true, the button is disabled and cannot be activated.
|
|
80
|
-
* @property {
|
|
82
|
+
* @property {string | string[]} theme - Theme(s) to be set as the theme attribute of the button, overriding any theme set on the menu bar.
|
|
81
83
|
* @property {SubMenuItem[]} children - Array of submenu items.
|
|
82
84
|
*/
|
|
83
85
|
|
|
@@ -85,7 +87,7 @@ export const MenuBarMixin = (superClass) =>
|
|
|
85
87
|
* @typedef SubMenuItem
|
|
86
88
|
* @type {object}
|
|
87
89
|
* @property {string} text - Text to be set as the menu item component's textContent.
|
|
88
|
-
* @property {
|
|
90
|
+
* @property {string | HTMLElement} component - The component to represent the item.
|
|
89
91
|
* Either a tagName or an element instance. Defaults to "vaadin-menu-bar-item".
|
|
90
92
|
* @property {boolean} disabled - If true, the item is disabled and cannot be selected.
|
|
91
93
|
* @property {boolean} checked - If true, the item shows a checkmark next to it.
|
|
@@ -134,12 +136,7 @@ export const MenuBarMixin = (superClass) =>
|
|
|
134
136
|
* which makes disabled buttons focusable and hoverable, while still
|
|
135
137
|
* preventing them from being triggered:
|
|
136
138
|
*
|
|
137
|
-
* ```
|
|
138
|
-
* // Set before any menu bar is attached to the DOM.
|
|
139
|
-
* window.Vaadin.featureFlags.accessibleDisabledButtons = true;
|
|
140
|
-
* ```
|
|
141
|
-
*
|
|
142
|
-
* ```
|
|
139
|
+
* ```js
|
|
143
140
|
* // Set before any menu bar is attached to the DOM.
|
|
144
141
|
* window.Vaadin.featureFlags.accessibleDisabledButtons = true;
|
|
145
142
|
* ```
|
|
@@ -152,16 +149,6 @@ export const MenuBarMixin = (superClass) =>
|
|
|
152
149
|
value: () => [],
|
|
153
150
|
},
|
|
154
151
|
|
|
155
|
-
/**
|
|
156
|
-
* A space-delimited list of CSS class names
|
|
157
|
-
* to set on each sub-menu overlay element.
|
|
158
|
-
*
|
|
159
|
-
* @attr {string} overlay-class
|
|
160
|
-
*/
|
|
161
|
-
overlayClass: {
|
|
162
|
-
type: String,
|
|
163
|
-
},
|
|
164
|
-
|
|
165
152
|
/**
|
|
166
153
|
* If true, the submenu will open on hover (mouseover) instead of click.
|
|
167
154
|
* @attr {boolean} open-on-hover
|
|
@@ -189,48 +176,16 @@ export const MenuBarMixin = (superClass) =>
|
|
|
189
176
|
type: Boolean,
|
|
190
177
|
sync: true,
|
|
191
178
|
},
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* @type {boolean}
|
|
195
|
-
* @protected
|
|
196
|
-
*/
|
|
197
|
-
_hasOverflow: {
|
|
198
|
-
type: Boolean,
|
|
199
|
-
value: false,
|
|
200
|
-
sync: true,
|
|
201
|
-
},
|
|
202
|
-
|
|
203
|
-
/** @protected */
|
|
204
|
-
_overflow: {
|
|
205
|
-
type: Object,
|
|
206
|
-
},
|
|
207
|
-
|
|
208
|
-
/** @protected */
|
|
209
|
-
_container: {
|
|
210
|
-
type: Object,
|
|
211
|
-
sync: true,
|
|
212
|
-
},
|
|
213
179
|
};
|
|
214
180
|
}
|
|
215
181
|
|
|
216
|
-
static get observers() {
|
|
217
|
-
return [
|
|
218
|
-
'_themeChanged(_theme, _overflow, _container)',
|
|
219
|
-
'__hasOverflowChanged(_hasOverflow, _overflow)',
|
|
220
|
-
'__i18nChanged(__effectiveI18n, _overflow)',
|
|
221
|
-
'__updateButtons(items, disabled, _overflow, _container)',
|
|
222
|
-
'_reverseCollapseChanged(reverseCollapse, _overflow, _container)',
|
|
223
|
-
'_tabNavigationChanged(tabNavigation, _overflow, _container)',
|
|
224
|
-
];
|
|
225
|
-
}
|
|
226
|
-
|
|
227
182
|
/**
|
|
228
183
|
* The object used to localize this component. To change the default
|
|
229
184
|
* localization, replace this with an object that provides all properties, or
|
|
230
185
|
* just the individual properties you want to change.
|
|
231
186
|
*
|
|
232
187
|
* The object has the following JSON structure and default values:
|
|
233
|
-
* ```
|
|
188
|
+
* ```js
|
|
234
189
|
* {
|
|
235
190
|
* moreOptions: 'More options'
|
|
236
191
|
* }
|
|
@@ -305,8 +260,15 @@ export const MenuBarMixin = (superClass) =>
|
|
|
305
260
|
}
|
|
306
261
|
|
|
307
262
|
/** @private */
|
|
308
|
-
get
|
|
309
|
-
return this.
|
|
263
|
+
get _hasOverflow() {
|
|
264
|
+
return this._overflow && !this._overflow.hasAttribute('hidden');
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** @private */
|
|
268
|
+
set _hasOverflow(hasOverflow) {
|
|
269
|
+
if (this._overflow) {
|
|
270
|
+
this._overflow.toggleAttribute('hidden', !hasOverflow);
|
|
271
|
+
}
|
|
310
272
|
}
|
|
311
273
|
|
|
312
274
|
/** @protected */
|
|
@@ -315,6 +277,20 @@ export const MenuBarMixin = (superClass) =>
|
|
|
315
277
|
|
|
316
278
|
this.setAttribute('role', 'menubar');
|
|
317
279
|
|
|
280
|
+
this._subMenuController = new SlotController(this, 'submenu', 'vaadin-menu-bar-submenu', {
|
|
281
|
+
initializer: (menu) => {
|
|
282
|
+
menu.setAttribute('is-root', '');
|
|
283
|
+
|
|
284
|
+
menu.addEventListener('item-selected', this.__onItemSelected.bind(this));
|
|
285
|
+
menu.addEventListener('close-all-menus', this.__onEscapeClose.bind(this));
|
|
286
|
+
|
|
287
|
+
const overlay = menu._overlayElement;
|
|
288
|
+
overlay._contentRoot.addEventListener('keydown', this.__boundOnContextMenuKeydown);
|
|
289
|
+
|
|
290
|
+
this._subMenu = menu;
|
|
291
|
+
},
|
|
292
|
+
});
|
|
293
|
+
|
|
318
294
|
this._overflowController = new SlotController(this, 'overflow', 'vaadin-menu-bar-button', {
|
|
319
295
|
initializer: (btn) => {
|
|
320
296
|
btn.setAttribute('hidden', '');
|
|
@@ -331,27 +307,47 @@ export const MenuBarMixin = (superClass) =>
|
|
|
331
307
|
this._overflow = btn;
|
|
332
308
|
},
|
|
333
309
|
});
|
|
310
|
+
|
|
311
|
+
this.addController(this._subMenuController);
|
|
334
312
|
this.addController(this._overflowController);
|
|
335
313
|
|
|
336
314
|
this.addEventListener('mousedown', () => this._hideTooltip(true));
|
|
337
315
|
this.addEventListener('mouseleave', () => this._hideTooltip());
|
|
338
316
|
|
|
339
|
-
this.
|
|
340
|
-
|
|
317
|
+
this._container = this.shadowRoot.querySelector('[part="container"]');
|
|
318
|
+
}
|
|
341
319
|
|
|
342
|
-
|
|
343
|
-
|
|
320
|
+
/** @protected */
|
|
321
|
+
updated(props) {
|
|
322
|
+
super.updated(props);
|
|
344
323
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
324
|
+
if (props.has('items') || props.has('_theme') || props.has('disabled')) {
|
|
325
|
+
this.__renderButtons(this.items);
|
|
326
|
+
}
|
|
348
327
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
328
|
+
if (props.has('items') || props.has('_theme') || props.has('reverseCollapse')) {
|
|
329
|
+
this.__scheduleOverflow();
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (props.has('items')) {
|
|
333
|
+
this.__updateSubMenu();
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (props.has('_theme')) {
|
|
337
|
+
this._themeChanged(this._theme);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (props.has('disabled')) {
|
|
341
|
+
this._overflow.toggleAttribute('disabled', this.disabled);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (props.has('tabNavigation')) {
|
|
345
|
+
this._tabNavigationChanged(this.tabNavigation);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (props.has('__effectiveI18n')) {
|
|
349
|
+
this.__i18nChanged(this.__effectiveI18n);
|
|
350
|
+
}
|
|
355
351
|
}
|
|
356
352
|
|
|
357
353
|
/**
|
|
@@ -380,87 +376,40 @@ export const MenuBarMixin = (superClass) =>
|
|
|
380
376
|
* @override
|
|
381
377
|
*/
|
|
382
378
|
_onResize() {
|
|
383
|
-
this.
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* A callback for the `_theme` property observer.
|
|
388
|
-
* It propagates the host theme to the buttons and the sub menu.
|
|
389
|
-
*
|
|
390
|
-
* @param {string | null} theme
|
|
391
|
-
* @private
|
|
392
|
-
*/
|
|
393
|
-
_themeChanged(theme, overflow, container) {
|
|
394
|
-
if (overflow && container) {
|
|
395
|
-
this.__renderButtons(this.items);
|
|
396
|
-
this.__detectOverflow();
|
|
397
|
-
|
|
398
|
-
if (theme) {
|
|
399
|
-
overflow.setAttribute('theme', theme);
|
|
400
|
-
this._subMenu.setAttribute('theme', theme);
|
|
401
|
-
} else {
|
|
402
|
-
overflow.removeAttribute('theme');
|
|
403
|
-
this._subMenu.removeAttribute('theme');
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
/**
|
|
409
|
-
* A callback for the 'reverseCollapse' property observer.
|
|
410
|
-
*
|
|
411
|
-
* @param {boolean | null} _reverseCollapse
|
|
412
|
-
* @private
|
|
413
|
-
*/
|
|
414
|
-
_reverseCollapseChanged(_reverseCollapse, overflow, container) {
|
|
415
|
-
if (overflow && container) {
|
|
416
|
-
this.__detectOverflow();
|
|
417
|
-
}
|
|
379
|
+
this.__scheduleOverflow();
|
|
418
380
|
}
|
|
419
381
|
|
|
420
382
|
/** @private */
|
|
421
|
-
|
|
422
|
-
if (
|
|
423
|
-
|
|
424
|
-
this.
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
this._setTabindex(btn, false);
|
|
429
|
-
}
|
|
430
|
-
btn.setAttribute('role', tabNavigation ? 'button' : 'menuitem');
|
|
431
|
-
});
|
|
383
|
+
_themeChanged(theme) {
|
|
384
|
+
if (theme) {
|
|
385
|
+
this._overflow.setAttribute('theme', theme);
|
|
386
|
+
this._subMenu.setAttribute('theme', theme);
|
|
387
|
+
} else {
|
|
388
|
+
this._overflow.removeAttribute('theme');
|
|
389
|
+
this._subMenu.removeAttribute('theme');
|
|
432
390
|
}
|
|
433
|
-
this.setAttribute('role', tabNavigation ? 'group' : 'menubar');
|
|
434
391
|
}
|
|
435
392
|
|
|
436
393
|
/** @private */
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
394
|
+
_tabNavigationChanged(tabNavigation) {
|
|
395
|
+
const target = this.querySelector('[tabindex="0"]');
|
|
396
|
+
this._buttons.forEach((btn) => {
|
|
397
|
+
if (target) {
|
|
398
|
+
this._setTabindex(btn, btn === target);
|
|
399
|
+
} else {
|
|
400
|
+
this._setTabindex(btn, false);
|
|
401
|
+
}
|
|
402
|
+
btn.setAttribute('role', tabNavigation ? 'button' : 'menuitem');
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
this.setAttribute('role', tabNavigation ? 'group' : 'menubar');
|
|
441
406
|
}
|
|
442
407
|
|
|
443
408
|
/** @private */
|
|
444
|
-
|
|
445
|
-
if (!overflow || !container) {
|
|
446
|
-
return;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
if (items !== this._oldItems) {
|
|
450
|
-
this._oldItems = items;
|
|
451
|
-
this.__renderButtons(items);
|
|
452
|
-
this.__detectOverflow();
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
if (disabled !== this._oldDisabled) {
|
|
456
|
-
this._oldDisabled = disabled;
|
|
457
|
-
this.__renderButtons(items);
|
|
458
|
-
overflow.toggleAttribute('disabled', disabled);
|
|
459
|
-
}
|
|
460
|
-
|
|
409
|
+
__updateSubMenu() {
|
|
461
410
|
const subMenu = this._subMenu;
|
|
462
411
|
if (subMenu && subMenu.opened) {
|
|
463
|
-
const button = subMenu.
|
|
412
|
+
const button = subMenu._positionTarget;
|
|
464
413
|
|
|
465
414
|
// Close sub-menu if the corresponding button is no longer in the DOM,
|
|
466
415
|
// or if the item on it has been changed to no longer have children.
|
|
@@ -471,12 +420,12 @@ export const MenuBarMixin = (superClass) =>
|
|
|
471
420
|
}
|
|
472
421
|
|
|
473
422
|
/** @private */
|
|
474
|
-
__i18nChanged(effectiveI18n
|
|
475
|
-
if (
|
|
423
|
+
__i18nChanged(effectiveI18n) {
|
|
424
|
+
if (effectiveI18n && effectiveI18n.moreOptions !== undefined) {
|
|
476
425
|
if (effectiveI18n.moreOptions) {
|
|
477
|
-
|
|
426
|
+
this._overflow.setAttribute('aria-label', effectiveI18n.moreOptions);
|
|
478
427
|
} else {
|
|
479
|
-
|
|
428
|
+
this._overflow.removeAttribute('aria-label');
|
|
480
429
|
}
|
|
481
430
|
}
|
|
482
431
|
}
|
|
@@ -561,11 +510,14 @@ export const MenuBarMixin = (superClass) =>
|
|
|
561
510
|
}
|
|
562
511
|
|
|
563
512
|
/** @private */
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
}
|
|
513
|
+
__scheduleOverflow() {
|
|
514
|
+
this._overflowDebouncer = Debouncer.debounce(this._overflowDebouncer, microTask, () => {
|
|
515
|
+
this.__detectOverflow();
|
|
516
|
+
});
|
|
517
|
+
}
|
|
568
518
|
|
|
519
|
+
/** @private */
|
|
520
|
+
__detectOverflow() {
|
|
569
521
|
const overflow = this._overflow;
|
|
570
522
|
const buttons = this._buttons.filter((btn) => btn !== overflow);
|
|
571
523
|
const oldOverflowCount = this.__getOverflowCount(overflow);
|
|
@@ -707,6 +659,7 @@ export const MenuBarMixin = (superClass) =>
|
|
|
707
659
|
_hideTooltip(immediate) {
|
|
708
660
|
const tooltip = this._tooltipController && this._tooltipController.node;
|
|
709
661
|
if (tooltip) {
|
|
662
|
+
this._tooltipController.setContext({ item: null });
|
|
710
663
|
tooltip._stateController.close(immediate);
|
|
711
664
|
}
|
|
712
665
|
}
|
|
@@ -740,17 +693,18 @@ export const MenuBarMixin = (superClass) =>
|
|
|
740
693
|
* and open another one for the newly focused button.
|
|
741
694
|
*
|
|
742
695
|
* @param {Element} item
|
|
696
|
+
* @param {FocusOptions=} options
|
|
743
697
|
* @param {boolean} navigating
|
|
744
698
|
* @protected
|
|
745
699
|
* @override
|
|
746
700
|
*/
|
|
747
|
-
_focusItem(item, navigating) {
|
|
701
|
+
_focusItem(item, options, navigating) {
|
|
748
702
|
const wasExpanded = navigating && this.focused === this._expandedButton;
|
|
749
703
|
if (wasExpanded) {
|
|
750
704
|
this._close();
|
|
751
705
|
}
|
|
752
706
|
|
|
753
|
-
super._focusItem(item, navigating);
|
|
707
|
+
super._focusItem(item, options, navigating);
|
|
754
708
|
|
|
755
709
|
this._buttons.forEach((btn) => {
|
|
756
710
|
this._setTabindex(btn, btn === item);
|
|
@@ -770,6 +724,34 @@ export const MenuBarMixin = (superClass) =>
|
|
|
770
724
|
return Array.from(e.composedPath()).find((el) => el.localName === 'vaadin-menu-bar-button');
|
|
771
725
|
}
|
|
772
726
|
|
|
727
|
+
/**
|
|
728
|
+
* Override method inherited from `FocusMixin`
|
|
729
|
+
*
|
|
730
|
+
* @override
|
|
731
|
+
* @protected
|
|
732
|
+
*/
|
|
733
|
+
_shouldSetFocus(event) {
|
|
734
|
+
// Ignore events from the submenu
|
|
735
|
+
if (event.composedPath().includes(this._subMenu)) {
|
|
736
|
+
return false;
|
|
737
|
+
}
|
|
738
|
+
return super._shouldSetFocus(event);
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* Override method inherited from `FocusMixin`
|
|
743
|
+
*
|
|
744
|
+
* @override
|
|
745
|
+
* @protected
|
|
746
|
+
*/
|
|
747
|
+
_shouldRemoveFocus(event) {
|
|
748
|
+
// Ignore events from the submenu
|
|
749
|
+
if (event.composedPath().includes(this._subMenu)) {
|
|
750
|
+
return false;
|
|
751
|
+
}
|
|
752
|
+
return super._shouldRemoveFocus(event);
|
|
753
|
+
}
|
|
754
|
+
|
|
773
755
|
/**
|
|
774
756
|
* Override method inherited from `FocusMixin`
|
|
775
757
|
*
|
|
@@ -852,6 +834,16 @@ export const MenuBarMixin = (superClass) =>
|
|
|
852
834
|
* @override
|
|
853
835
|
*/
|
|
854
836
|
_onKeyDown(event) {
|
|
837
|
+
// Ignore events from the submenu
|
|
838
|
+
if (event.composedPath().includes(this._subMenu)) {
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
this._handleKeyDown(event);
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
/** @private */
|
|
846
|
+
_handleKeyDown(event) {
|
|
855
847
|
switch (event.key) {
|
|
856
848
|
case 'ArrowDown':
|
|
857
849
|
this._onArrowDown(event);
|
|
@@ -866,11 +858,16 @@ export const MenuBarMixin = (superClass) =>
|
|
|
866
858
|
}
|
|
867
859
|
|
|
868
860
|
/**
|
|
869
|
-
* @param {!MouseEvent}
|
|
861
|
+
* @param {!MouseEvent} event
|
|
870
862
|
* @protected
|
|
871
863
|
*/
|
|
872
|
-
_onMouseOver(
|
|
873
|
-
|
|
864
|
+
_onMouseOver(event) {
|
|
865
|
+
// Ignore events from the submenu
|
|
866
|
+
if (event.composedPath().includes(this._subMenu)) {
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
const button = this._getButtonFromEvent(event);
|
|
874
871
|
if (!button) {
|
|
875
872
|
// Hide tooltip on mouseover to disabled button
|
|
876
873
|
this._hideTooltip();
|
|
@@ -902,11 +899,11 @@ export const MenuBarMixin = (superClass) =>
|
|
|
902
899
|
if (e.keyCode === 37 || (e.keyCode === 39 && !item._item.children)) {
|
|
903
900
|
// Prevent ArrowLeft from being handled in context-menu
|
|
904
901
|
e.stopImmediatePropagation();
|
|
905
|
-
this.
|
|
902
|
+
this._handleKeyDown(e);
|
|
906
903
|
}
|
|
907
904
|
|
|
908
905
|
if (e.key === 'Tab' && this.tabNavigation) {
|
|
909
|
-
this.
|
|
906
|
+
this._handleKeyDown(e);
|
|
910
907
|
}
|
|
911
908
|
}
|
|
912
909
|
}
|
|
@@ -948,6 +945,7 @@ export const MenuBarMixin = (superClass) =>
|
|
|
948
945
|
|
|
949
946
|
subMenu.items = items;
|
|
950
947
|
subMenu.listenOn = button;
|
|
948
|
+
subMenu._positionTarget = button;
|
|
951
949
|
const overlay = subMenu._overlayElement;
|
|
952
950
|
overlay.noVerticalOverlap = true;
|
|
953
951
|
|
|
@@ -957,7 +955,6 @@ export const MenuBarMixin = (superClass) =>
|
|
|
957
955
|
this._setExpanded(button, true);
|
|
958
956
|
|
|
959
957
|
this.style.pointerEvents = 'auto';
|
|
960
|
-
overlay.positionTarget = button;
|
|
961
958
|
|
|
962
959
|
button.dispatchEvent(
|
|
963
960
|
new CustomEvent('opensubmenu', {
|
|
@@ -975,7 +972,8 @@ export const MenuBarMixin = (superClass) =>
|
|
|
975
972
|
}
|
|
976
973
|
|
|
977
974
|
if (options.keepFocus) {
|
|
978
|
-
|
|
975
|
+
const focusOptions = { focusVisible: isKeyboardActive() };
|
|
976
|
+
this._focusItem(this._expandedButton, focusOptions, false);
|
|
979
977
|
}
|
|
980
978
|
|
|
981
979
|
// Do not focus item when open not from keyboard
|
|
@@ -989,13 +987,13 @@ export const MenuBarMixin = (superClass) =>
|
|
|
989
987
|
|
|
990
988
|
/** @private */
|
|
991
989
|
_focusFirstItem() {
|
|
992
|
-
const list = this._subMenu._overlayElement.firstElementChild;
|
|
990
|
+
const list = this._subMenu._overlayElement._contentRoot.firstElementChild;
|
|
993
991
|
list.focus();
|
|
994
992
|
}
|
|
995
993
|
|
|
996
994
|
/** @private */
|
|
997
995
|
_focusLastItem() {
|
|
998
|
-
const list = this._subMenu._overlayElement.firstElementChild;
|
|
996
|
+
const list = this._subMenu._overlayElement._contentRoot.firstElementChild;
|
|
999
997
|
const item = list.items[list.items.length - 1];
|
|
1000
998
|
if (item) {
|
|
1001
999
|
item.focus();
|
|
@@ -1019,7 +1017,8 @@ export const MenuBarMixin = (superClass) =>
|
|
|
1019
1017
|
if (button && button.hasAttribute('expanded')) {
|
|
1020
1018
|
this._setExpanded(button, false);
|
|
1021
1019
|
if (restoreFocus) {
|
|
1022
|
-
|
|
1020
|
+
const focusOptions = { focusVisible: isKeyboardActive() };
|
|
1021
|
+
this._focusItem(button, focusOptions, false);
|
|
1023
1022
|
}
|
|
1024
1023
|
this._expandedButton = null;
|
|
1025
1024
|
}
|
|
@@ -8,10 +8,10 @@ import { defineCustomElement } from '@vaadin/component-base/src/define.js';
|
|
|
8
8
|
import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
|
|
9
9
|
import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
|
|
10
10
|
import { MenuOverlayMixin } from '@vaadin/context-menu/src/vaadin-menu-overlay-mixin.js';
|
|
11
|
-
import { styles } from '@vaadin/context-menu/src/vaadin-menu-overlay-styles.js';
|
|
12
11
|
import { OverlayMixin } from '@vaadin/overlay/src/vaadin-overlay-mixin.js';
|
|
13
|
-
import {
|
|
12
|
+
import { LumoInjectionMixin } from '@vaadin/vaadin-themable-mixin/lumo-injection-mixin.js';
|
|
14
13
|
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
14
|
+
import { menuBarOverlayStyles } from './styles/vaadin-menu-bar-overlay-base-styles.js';
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* An element used internally by `<vaadin-menu-bar>`. Not intended to be used separately.
|
|
@@ -24,13 +24,15 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
|
|
|
24
24
|
* @mixes ThemableMixin
|
|
25
25
|
* @protected
|
|
26
26
|
*/
|
|
27
|
-
export class MenuBarOverlay extends MenuOverlayMixin(
|
|
27
|
+
export class MenuBarOverlay extends MenuOverlayMixin(
|
|
28
|
+
OverlayMixin(DirMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))),
|
|
29
|
+
) {
|
|
28
30
|
static get is() {
|
|
29
31
|
return 'vaadin-menu-bar-overlay';
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
static get styles() {
|
|
33
|
-
return
|
|
35
|
+
return menuBarOverlayStyles;
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
/** @protected */
|
|
@@ -40,6 +42,7 @@ export class MenuBarOverlay extends MenuOverlayMixin(OverlayMixin(DirMixin(Thema
|
|
|
40
42
|
<div part="overlay" id="overlay" tabindex="0">
|
|
41
43
|
<div part="content" id="content">
|
|
42
44
|
<slot></slot>
|
|
45
|
+
<slot name="submenu"></slot>
|
|
43
46
|
</div>
|
|
44
47
|
</div>
|
|
45
48
|
`;
|
|
@@ -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 };
|