@vaadin/menu-bar 24.8.0-alpha8 → 25.0.0-alpha1

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.
Files changed (39) hide show
  1. package/README.md +0 -23
  2. package/package.json +15 -18
  3. package/src/vaadin-menu-bar-button.js +19 -16
  4. package/src/vaadin-menu-bar-item.js +17 -12
  5. package/src/vaadin-menu-bar-list-box.d.ts +1 -2
  6. package/src/vaadin-menu-bar-list-box.js +27 -23
  7. package/src/vaadin-menu-bar-mixin.d.ts +2 -5
  8. package/src/vaadin-menu-bar-mixin.js +143 -153
  9. package/src/vaadin-menu-bar-overlay.js +11 -9
  10. package/src/vaadin-menu-bar-submenu.js +18 -21
  11. package/src/vaadin-menu-bar.js +28 -24
  12. package/web-types.json +2 -2
  13. package/web-types.lit.json +2 -2
  14. package/src/vaadin-lit-menu-bar-button.js +0 -67
  15. package/src/vaadin-lit-menu-bar-item.js +0 -62
  16. package/src/vaadin-lit-menu-bar-list-box.js +0 -87
  17. package/src/vaadin-lit-menu-bar-overlay.js +0 -49
  18. package/src/vaadin-lit-menu-bar-submenu.js +0 -57
  19. package/src/vaadin-lit-menu-bar.js +0 -83
  20. package/theme/lumo/vaadin-lit-menu-bar.d.ts +0 -6
  21. package/theme/lumo/vaadin-lit-menu-bar.js +0 -6
  22. package/theme/material/vaadin-lit-menu-bar.d.ts +0 -6
  23. package/theme/material/vaadin-lit-menu-bar.js +0 -6
  24. package/theme/material/vaadin-menu-bar-button-styles.d.ts +0 -1
  25. package/theme/material/vaadin-menu-bar-button-styles.js +0 -111
  26. package/theme/material/vaadin-menu-bar-button.d.ts +0 -2
  27. package/theme/material/vaadin-menu-bar-button.js +0 -2
  28. package/theme/material/vaadin-menu-bar-item-styles.d.ts +0 -1
  29. package/theme/material/vaadin-menu-bar-item-styles.js +0 -23
  30. package/theme/material/vaadin-menu-bar-list-box-styles.d.ts +0 -1
  31. package/theme/material/vaadin-menu-bar-list-box-styles.js +0 -5
  32. package/theme/material/vaadin-menu-bar-overlay-styles.d.ts +0 -1
  33. package/theme/material/vaadin-menu-bar-overlay-styles.js +0 -13
  34. package/theme/material/vaadin-menu-bar-styles.d.ts +0 -1
  35. package/theme/material/vaadin-menu-bar-styles.js +0 -21
  36. package/theme/material/vaadin-menu-bar.d.ts +0 -6
  37. package/theme/material/vaadin-menu-bar.js +0 -6
  38. package/vaadin-lit-menu-bar.d.ts +0 -1
  39. package/vaadin-lit-menu-bar.js +0 -2
@@ -3,22 +3,58 @@
3
3
  * Copyright (c) 2019 - 2025 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
+ import { html, noChange, nothing, render } from 'lit';
7
+ import { Directive, directive } from 'lit/directive.js';
8
+ import { ifDefined } from 'lit/directives/if-defined.js';
6
9
  import { DisabledMixin } from '@vaadin/a11y-base/src/disabled-mixin.js';
7
10
  import { FocusMixin } from '@vaadin/a11y-base/src/focus-mixin.js';
8
- import { isElementFocused, isElementHidden, isKeyboardActive } from '@vaadin/a11y-base/src/focus-utils.js';
11
+ import { isElementFocused, isKeyboardActive } from '@vaadin/a11y-base/src/focus-utils.js';
9
12
  import { KeyboardDirectionMixin } from '@vaadin/a11y-base/src/keyboard-direction-mixin.js';
10
- import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
11
13
  import { I18nMixin } from '@vaadin/component-base/src/i18n-mixin.js';
12
14
  import { ResizeMixin } from '@vaadin/component-base/src/resize-mixin.js';
13
15
  import { SlotController } from '@vaadin/component-base/src/slot-controller.js';
14
16
 
17
+ /**
18
+ * Custom Lit directive for rendering item components
19
+ * inspired by the `flowComponentDirective` logic.
20
+ */
21
+ class ItemComponentDirective extends Directive {
22
+ update(part, [{ component, text }]) {
23
+ const { parentNode, startNode } = part;
24
+
25
+ const newNode = component || (text ? document.createTextNode(text) : null);
26
+ const oldNode = this.getOldNode(part);
27
+
28
+ if (oldNode === newNode) {
29
+ return noChange;
30
+ } else if (oldNode && newNode) {
31
+ parentNode.replaceChild(newNode, oldNode);
32
+ } else if (oldNode) {
33
+ parentNode.removeChild(oldNode);
34
+ } else if (newNode) {
35
+ startNode.after(newNode);
36
+ }
37
+
38
+ return noChange;
39
+ }
40
+
41
+ getOldNode(part) {
42
+ const { startNode, endNode } = part;
43
+ if (startNode.nextSibling === endNode) {
44
+ return null;
45
+ }
46
+ return startNode.nextSibling;
47
+ }
48
+ }
49
+
50
+ const componentDirective = directive(ItemComponentDirective);
51
+
15
52
  const DEFAULT_I18N = {
16
53
  moreOptions: 'More options',
17
54
  };
18
55
 
19
56
  /**
20
57
  * @polymerMixin
21
- * @mixes ControllerMixin
22
58
  * @mixes DisabledMixin
23
59
  * @mixes FocusMixin
24
60
  * @mixes I18nMixin
@@ -28,7 +64,7 @@ const DEFAULT_I18N = {
28
64
  export const MenuBarMixin = (superClass) =>
29
65
  class MenuBarMixinClass extends I18nMixin(
30
66
  DEFAULT_I18N,
31
- KeyboardDirectionMixin(ResizeMixin(FocusMixin(DisabledMixin(ControllerMixin(superClass))))),
67
+ KeyboardDirectionMixin(ResizeMixin(FocusMixin(DisabledMixin(superClass)))),
32
68
  ) {
33
69
  static get properties() {
34
70
  return {
@@ -112,6 +148,7 @@ export const MenuBarMixin = (superClass) =>
112
148
  */
113
149
  items: {
114
150
  type: Array,
151
+ sync: true,
115
152
  value: () => [],
116
153
  },
117
154
 
@@ -140,6 +177,7 @@ export const MenuBarMixin = (superClass) =>
140
177
  */
141
178
  reverseCollapse: {
142
179
  type: Boolean,
180
+ sync: true,
143
181
  },
144
182
 
145
183
  /**
@@ -149,6 +187,7 @@ export const MenuBarMixin = (superClass) =>
149
187
  */
150
188
  tabNavigation: {
151
189
  type: Boolean,
190
+ sync: true,
152
191
  },
153
192
 
154
193
  /**
@@ -169,6 +208,7 @@ export const MenuBarMixin = (superClass) =>
169
208
  /** @protected */
170
209
  _container: {
171
210
  type: Object,
211
+ sync: true,
172
212
  },
173
213
  };
174
214
  }
@@ -178,7 +218,7 @@ export const MenuBarMixin = (superClass) =>
178
218
  '_themeChanged(_theme, _overflow, _container)',
179
219
  '__hasOverflowChanged(_hasOverflow, _overflow)',
180
220
  '__i18nChanged(__effectiveI18n, _overflow)',
181
- '_menuItemsChanged(items, _overflow, _container)',
221
+ '__updateButtons(items, disabled, _overflow, _container)',
182
222
  '_reverseCollapseChanged(reverseCollapse, _overflow, _container)',
183
223
  '_tabNavigationChanged(tabNavigation, _overflow, _container)',
184
224
  ];
@@ -235,6 +275,17 @@ export const MenuBarMixin = (superClass) =>
235
275
  return false;
236
276
  }
237
277
 
278
+ /**
279
+ * Override getter from `KeyboardDirectionMixin`.
280
+ *
281
+ * @return {boolean}
282
+ * @protected
283
+ * @override
284
+ */
285
+ get _tabNavigation() {
286
+ return this.tabNavigation;
287
+ }
288
+
238
289
  /**
239
290
  * Override getter from `ResizeMixin` to observe parent.
240
291
  *
@@ -273,8 +324,11 @@ export const MenuBarMixin = (superClass) =>
273
324
  dots.innerHTML = '·'.repeat(3);
274
325
  btn.appendChild(dots);
275
326
 
327
+ btn.setAttribute('aria-haspopup', 'true');
328
+ btn.setAttribute('aria-expanded', 'false');
329
+ btn.setAttribute('role', this.tabNavigation ? 'button' : 'menuitem');
330
+
276
331
  this._overflow = btn;
277
- this._initButtonAttrs(btn);
278
332
  },
279
333
  });
280
334
  this.addController(this._overflowController);
@@ -329,23 +383,6 @@ export const MenuBarMixin = (superClass) =>
329
383
  this.__detectOverflow();
330
384
  }
331
385
 
332
- /**
333
- * Override method inherited from `DisabledMixin`
334
- * to update the `disabled` property for the buttons
335
- * whenever the property changes on the menu bar.
336
- *
337
- * @param {boolean} newValue the new disabled value
338
- * @param {boolean} oldValue the previous disabled value
339
- * @override
340
- * @protected
341
- */
342
- _disabledChanged(newValue, oldValue) {
343
- super._disabledChanged(newValue, oldValue);
344
- if (oldValue !== newValue) {
345
- this.__updateButtonsDisabled(newValue);
346
- }
347
- }
348
-
349
386
  /**
350
387
  * A callback for the `_theme` property observer.
351
388
  * It propagates the host theme to the buttons and the sub menu.
@@ -355,14 +392,16 @@ export const MenuBarMixin = (superClass) =>
355
392
  */
356
393
  _themeChanged(theme, overflow, container) {
357
394
  if (overflow && container) {
358
- this._buttons.forEach((btn) => this._setButtonTheme(btn, theme));
395
+ this.__renderButtons(this.items);
359
396
  this.__detectOverflow();
360
- }
361
397
 
362
- if (theme) {
363
- this._subMenu.setAttribute('theme', theme);
364
- } else {
365
- this._subMenu.removeAttribute('theme');
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
+ }
366
405
  }
367
406
  }
368
407
 
@@ -402,7 +441,7 @@ export const MenuBarMixin = (superClass) =>
402
441
  }
403
442
 
404
443
  /** @private */
405
- _menuItemsChanged(items, overflow, container) {
444
+ __updateButtons(items, disabled, overflow, container) {
406
445
  if (!overflow || !container) {
407
446
  return;
408
447
  }
@@ -410,11 +449,24 @@ export const MenuBarMixin = (superClass) =>
410
449
  if (items !== this._oldItems) {
411
450
  this._oldItems = items;
412
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);
413
459
  }
414
460
 
415
461
  const subMenu = this._subMenu;
416
462
  if (subMenu && subMenu.opened) {
417
- subMenu.close();
463
+ const button = subMenu._overlayElement.positionTarget;
464
+
465
+ // Close sub-menu if the corresponding button is no longer in the DOM,
466
+ // or if the item on it has been changed to no longer have children.
467
+ if (!button.isConnected || !Array.isArray(button.item.children) || button.item.children.length === 0) {
468
+ subMenu.close();
469
+ }
418
470
  }
419
471
  }
420
472
 
@@ -438,9 +490,9 @@ export const MenuBarMixin = (superClass) =>
438
490
  /** @private */
439
491
  __restoreButtons(buttons) {
440
492
  buttons.forEach((button) => {
441
- button.disabled = (button.item && button.item.disabled) || this.disabled;
442
493
  button.style.visibility = '';
443
494
  button.style.position = '';
495
+ button.style.width = '';
444
496
 
445
497
  // Teleport item component back from "overflow" sub-menu
446
498
  const item = button.item && button.item.component;
@@ -460,14 +512,6 @@ export const MenuBarMixin = (superClass) =>
460
512
  item.removeAttribute('tabindex');
461
513
  }
462
514
 
463
- /** @private */
464
- __updateButtonsDisabled(disabled) {
465
- this._buttons.forEach((btn) => {
466
- // Disable the button if the entire menu-bar is disabled or the item alone is disabled
467
- btn.disabled = disabled || (btn.item && btn.item.disabled);
468
- });
469
- }
470
-
471
515
  /** @private */
472
516
  __updateOverflow(items) {
473
517
  this._overflow.item = { children: items };
@@ -501,7 +545,6 @@ export const MenuBarMixin = (superClass) =>
501
545
 
502
546
  // Save width for buttons with component
503
547
  btn.style.width = getComputedStyle(btn).width;
504
- btn.disabled = true;
505
548
  btn.style.visibility = 'hidden';
506
549
  btn.style.position = 'absolute';
507
550
  }
@@ -550,66 +593,17 @@ export const MenuBarMixin = (superClass) =>
550
593
  });
551
594
  }
552
595
 
553
- /** @protected */
554
- _removeButtons() {
555
- this._buttons.forEach((button) => {
556
- if (button !== this._overflow) {
557
- this.removeChild(button);
558
- }
559
- });
560
- }
561
-
562
- /** @protected */
563
- _initButton(item) {
564
- const button = document.createElement('vaadin-menu-bar-button');
565
-
566
- const itemCopy = { ...item };
567
- button.item = itemCopy;
568
-
569
- if (item.component) {
570
- const component = this.__getComponent(itemCopy);
571
- itemCopy.component = component;
572
- // Save item for overflow menu
573
- component.item = itemCopy;
574
- button.appendChild(component);
575
- } else if (item.text) {
576
- button.textContent = item.text;
577
- }
578
-
579
- if (item.className) {
580
- button.className = item.className;
581
- }
582
-
583
- button.disabled = item.disabled;
584
-
585
- return button;
586
- }
587
-
588
- /** @protected */
589
- _initButtonAttrs(button) {
590
- button.setAttribute('role', this.tabNavigation ? 'button' : 'menuitem');
591
-
592
- if (button === this._overflow || (button.item && button.item.children)) {
593
- button.setAttribute('aria-haspopup', 'true');
594
- button.setAttribute('aria-expanded', 'false');
595
- }
596
- }
597
-
598
- /** @protected */
599
- _setButtonTheme(btn, hostTheme) {
596
+ /** @private */
597
+ __getButtonTheme(item, hostTheme) {
600
598
  let theme = hostTheme;
601
599
 
602
600
  // Item theme takes precedence over host theme even if it's empty, as long as it's not undefined or null
603
- const itemTheme = btn.item && btn.item.theme;
601
+ const itemTheme = item && item.theme;
604
602
  if (itemTheme != null) {
605
603
  theme = Array.isArray(itemTheme) ? itemTheme.join(' ') : itemTheme;
606
604
  }
607
605
 
608
- if (theme) {
609
- btn.setAttribute('theme', theme);
610
- } else {
611
- btn.removeAttribute('theme');
612
- }
606
+ return theme;
613
607
  }
614
608
 
615
609
  /** @private */
@@ -634,21 +628,47 @@ export const MenuBarMixin = (superClass) =>
634
628
 
635
629
  /** @private */
636
630
  __renderButtons(items = []) {
637
- this._removeButtons();
638
-
639
- /* Empty array, do nothing */
640
- if (items.length === 0) {
641
- return;
642
- }
631
+ render(
632
+ html`
633
+ ${items.map((item) => {
634
+ const itemCopy = { ...item };
635
+ const hasChildren = Boolean(item && item.children);
636
+
637
+ if (itemCopy.component) {
638
+ const component = this.__getComponent(itemCopy);
639
+ itemCopy.component = component;
640
+ component.item = itemCopy;
641
+ }
643
642
 
644
- items.forEach((item) => {
645
- const button = this._initButton(item);
646
- this.insertBefore(button, this._overflow);
647
- this._initButtonAttrs(button);
648
- this._setButtonTheme(button, this._theme);
649
- });
643
+ return html`
644
+ <vaadin-menu-bar-button
645
+ .item="${itemCopy}"
646
+ .disabled="${this.disabled || item.disabled}"
647
+ role="${this.tabNavigation ? 'button' : 'menuitem'}"
648
+ aria-haspopup="${ifDefined(hasChildren ? 'true' : nothing)}"
649
+ aria-expanded="${ifDefined(hasChildren ? 'false' : nothing)}"
650
+ class="${ifDefined(item.className || nothing)}"
651
+ theme="${ifDefined(this.__getButtonTheme(item, this._theme) || nothing)}"
652
+ @click="${this.__onRootButtonClick}"
653
+ >${componentDirective(itemCopy)}</vaadin-menu-bar-button
654
+ >
655
+ `;
656
+ })}
657
+ `,
658
+ this,
659
+ { renderBefore: this._overflow },
660
+ );
661
+ }
650
662
 
651
- this.__detectOverflow();
663
+ /** @private */
664
+ __onRootButtonClick(event) {
665
+ const button = event.target;
666
+ // Propagate click event from button to the item component if it was outside
667
+ // it e.g. by calling `click()` on the button (used by the Flow counterpart).
668
+ if (button.item && button.item.component && !event.composedPath().includes(button.item.component)) {
669
+ event.stopPropagation();
670
+ button.item.component.click();
671
+ }
652
672
  }
653
673
 
654
674
  /**
@@ -759,12 +779,7 @@ export const MenuBarMixin = (superClass) =>
759
779
  */
760
780
  _setFocused(focused) {
761
781
  if (focused) {
762
- let target = this.querySelector('[tabindex="0"]');
763
- if (this.tabNavigation) {
764
- // Switch submenu on menu button Tab / Shift Tab
765
- target = this.querySelector('[focused]');
766
- this.__switchSubMenu(target);
767
- }
782
+ const target = this.tabNavigation ? this.querySelector('[focused]') : this.querySelector('[tabindex="0"]');
768
783
  if (target) {
769
784
  this._buttons.forEach((btn) => {
770
785
  this._setTabindex(btn, btn === target);
@@ -883,30 +898,15 @@ export const MenuBarMixin = (superClass) =>
883
898
  if (e.keyCode === 38 && item === list.items[0]) {
884
899
  this._close(true);
885
900
  }
886
- // ArrowLeft, or ArrowRight on non-parent submenu item
901
+ // ArrowLeft, or ArrowRight on non-parent submenu item,
887
902
  if (e.keyCode === 37 || (e.keyCode === 39 && !item._item.children)) {
888
903
  // Prevent ArrowLeft from being handled in context-menu
889
904
  e.stopImmediatePropagation();
890
905
  this._onKeyDown(e);
891
- } else if (e.keyCode === 9 && this.tabNavigation) {
892
- // Switch opened submenu on submenu item Tab / Shift Tab
893
- const items = this._getItems() || [];
894
- const currentIdx = items.indexOf(this.focused);
895
- const increment = e.shiftKey ? -1 : 1;
896
- let idx = currentIdx + increment;
897
- idx = this._getAvailableIndex(items, idx, increment, (item) => !isElementHidden(item));
898
- this.__switchSubMenu(items[idx]);
899
906
  }
900
- }
901
- }
902
907
 
903
- /** @private */
904
- __switchSubMenu(target) {
905
- const wasExpanded = this._expandedButton != null && this._expandedButton !== target;
906
- if (wasExpanded) {
907
- this._close();
908
- if (target.item && target.item.children) {
909
- this.__openSubMenu(target, true, { keepFocus: true });
908
+ if (e.key === 'Tab' && this.tabNavigation) {
909
+ this._onKeyDown(e);
910
910
  }
911
911
  }
912
912
  }
@@ -951,31 +951,21 @@ export const MenuBarMixin = (superClass) =>
951
951
  const overlay = subMenu._overlayElement;
952
952
  overlay.noVerticalOverlap = true;
953
953
 
954
- this._expandedButton = button;
955
-
956
- requestAnimationFrame(() => {
957
- // After changing items, buttons are recreated so the old button is
958
- // no longer in the DOM. Reset position target to null to prevent
959
- // overlay from closing due to target width / height equal to 0.
960
- if (overlay.positionTarget && !overlay.positionTarget.isConnected) {
961
- overlay.positionTarget = null;
962
- }
963
-
964
- button.dispatchEvent(
965
- new CustomEvent('opensubmenu', {
966
- detail: {
967
- children: items,
968
- },
969
- }),
970
- );
971
- this._hideTooltip(true);
972
-
973
- this._setExpanded(button, true);
954
+ this._hideTooltip(true);
974
955
 
975
- overlay.positionTarget = button;
976
- });
956
+ this._expandedButton = button;
957
+ this._setExpanded(button, true);
977
958
 
978
959
  this.style.pointerEvents = 'auto';
960
+ overlay.positionTarget = button;
961
+
962
+ button.dispatchEvent(
963
+ new CustomEvent('opensubmenu', {
964
+ detail: {
965
+ children: items,
966
+ },
967
+ }),
968
+ );
979
969
 
980
970
  overlay.addEventListener(
981
971
  'vaadin-overlay-open',
@@ -3,18 +3,15 @@
3
3
  * Copyright (c) 2019 - 2025 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
- import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
6
+ import { html, LitElement } from 'lit';
7
7
  import { defineCustomElement } from '@vaadin/component-base/src/define.js';
8
8
  import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
9
+ import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
9
10
  import { MenuOverlayMixin } from '@vaadin/context-menu/src/vaadin-menu-overlay-mixin.js';
10
11
  import { styles } from '@vaadin/context-menu/src/vaadin-menu-overlay-styles.js';
11
12
  import { OverlayMixin } from '@vaadin/overlay/src/vaadin-overlay-mixin.js';
12
13
  import { overlayStyles } from '@vaadin/overlay/src/vaadin-overlay-styles.js';
13
- import { registerStyles, ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
14
-
15
- registerStyles('vaadin-menu-bar-overlay', [overlayStyles, styles], {
16
- moduleId: 'vaadin-menu-bar-overlay-styles',
17
- });
14
+ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
18
15
 
19
16
  /**
20
17
  * An element used internally by `<vaadin-menu-bar>`. Not intended to be used separately.
@@ -27,14 +24,19 @@ registerStyles('vaadin-menu-bar-overlay', [overlayStyles, styles], {
27
24
  * @mixes ThemableMixin
28
25
  * @protected
29
26
  */
30
- export class MenuBarOverlay extends MenuOverlayMixin(OverlayMixin(DirMixin(ThemableMixin(PolymerElement)))) {
27
+ export class MenuBarOverlay extends MenuOverlayMixin(OverlayMixin(DirMixin(ThemableMixin(PolylitMixin(LitElement))))) {
31
28
  static get is() {
32
29
  return 'vaadin-menu-bar-overlay';
33
30
  }
34
31
 
35
- static get template() {
32
+ static get styles() {
33
+ return [overlayStyles, styles];
34
+ }
35
+
36
+ /** @protected */
37
+ render() {
36
38
  return html`
37
- <div id="backdrop" part="backdrop" hidden$="[[!withBackdrop]]"></div>
39
+ <div id="backdrop" part="backdrop" ?hidden="${!this.withBackdrop}"></div>
38
40
  <div part="overlay" id="overlay" tabindex="0">
39
41
  <div part="content" id="content">
40
42
  <slot></slot>
@@ -6,9 +6,9 @@
6
6
  import './vaadin-menu-bar-item.js';
7
7
  import './vaadin-menu-bar-list-box.js';
8
8
  import './vaadin-menu-bar-overlay.js';
9
- import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
10
- import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
9
+ import { css, html, LitElement } from 'lit';
11
10
  import { defineCustomElement } from '@vaadin/component-base/src/define.js';
11
+ import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
12
12
  import { ThemePropertyMixin } from '@vaadin/vaadin-themable-mixin/vaadin-theme-property-mixin.js';
13
13
  import { SubMenuMixin } from './vaadin-menu-bar-submenu-mixin.js';
14
14
 
@@ -17,41 +17,38 @@ import { SubMenuMixin } from './vaadin-menu-bar-submenu-mixin.js';
17
17
  *
18
18
  * @customElement
19
19
  * @extends HTMLElement
20
- * @mixes ControllerMixin
21
20
  * @mixes SubMenuMixin
22
21
  * @mixes ThemePropertyMixin
23
22
  * @protected
24
23
  */
25
- class MenuBarSubmenu extends SubMenuMixin(ControllerMixin(ThemePropertyMixin(PolymerElement))) {
24
+ class MenuBarSubmenu extends SubMenuMixin(ThemePropertyMixin(PolylitMixin(LitElement))) {
26
25
  static get is() {
27
26
  return 'vaadin-menu-bar-submenu';
28
27
  }
29
28
 
30
- static get template() {
31
- return html`
32
- <style>
33
- :host {
34
- display: block;
35
- }
29
+ static get styles() {
30
+ return css`
31
+ :host {
32
+ display: block;
33
+ }
36
34
 
37
- :host([hidden]) {
38
- display: none !important;
39
- }
40
- </style>
41
-
42
- <slot id="slot"></slot>
35
+ :host([hidden]) {
36
+ display: none !important;
37
+ }
43
38
  `;
44
39
  }
45
40
 
41
+ /** @protected */
42
+ render() {
43
+ return html`<slot id="slot"></slot>`;
44
+ }
45
+
46
46
  /**
47
- * @param {DocumentFragment} dom
48
- * @return {ShadowRoot}
49
47
  * @protected
50
48
  * @override
51
49
  */
52
- _attachDom(dom) {
53
- const root = this.attachShadow({ mode: 'open' });
54
- root.appendChild(dom);
50
+ createRenderRoot() {
51
+ const root = super.createRenderRoot();
55
52
  root.appendChild(this._overlayElement);
56
53
  return root;
57
54
  }
@@ -5,9 +5,10 @@
5
5
  */
6
6
  import './vaadin-menu-bar-submenu.js';
7
7
  import './vaadin-menu-bar-button.js';
8
- import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
8
+ import { css, html, LitElement } from 'lit';
9
9
  import { defineCustomElement } from '@vaadin/component-base/src/define.js';
10
10
  import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
11
+ import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
11
12
  import { TooltipController } from '@vaadin/component-base/src/tooltip-controller.js';
12
13
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
13
14
  import { MenuBarMixin } from './vaadin-menu-bar-mixin.js';
@@ -74,41 +75,44 @@ import { MenuBarMixin } from './vaadin-menu-bar-mixin.js';
74
75
  * @mixes MenuBarMixin
75
76
  * @mixes ThemableMixin
76
77
  */
77
- class MenuBar extends MenuBarMixin(ElementMixin(ThemableMixin(PolymerElement))) {
78
- static get template() {
79
- return html`
80
- <style>
81
- :host {
82
- display: block;
83
- }
78
+ class MenuBar extends MenuBarMixin(ElementMixin(ThemableMixin(PolylitMixin(LitElement)))) {
79
+ static get is() {
80
+ return 'vaadin-menu-bar';
81
+ }
84
82
 
85
- :host([hidden]) {
86
- display: none !important;
87
- }
83
+ static get styles() {
84
+ return css`
85
+ :host {
86
+ display: block;
87
+ }
88
88
 
89
- [part='container'] {
90
- position: relative;
91
- display: flex;
92
- width: 100%;
93
- flex-wrap: nowrap;
94
- overflow: hidden;
95
- }
96
- </style>
89
+ :host([hidden]) {
90
+ display: none !important;
91
+ }
92
+
93
+ [part='container'] {
94
+ position: relative;
95
+ display: flex;
96
+ width: 100%;
97
+ flex-wrap: nowrap;
98
+ overflow: hidden;
99
+ }
100
+ `;
101
+ }
97
102
 
103
+ /** @protected */
104
+ render() {
105
+ return html`
98
106
  <div part="container">
99
107
  <slot></slot>
100
108
  <slot name="overflow"></slot>
101
109
  </div>
102
- <vaadin-menu-bar-submenu is-root overlay-class="[[overlayClass]]"></vaadin-menu-bar-submenu>
110
+ <vaadin-menu-bar-submenu is-root .overlayClass="${this.overlayClass}"></vaadin-menu-bar-submenu>
103
111
 
104
112
  <slot name="tooltip"></slot>
105
113
  `;
106
114
  }
107
115
 
108
- static get is() {
109
- return 'vaadin-menu-bar';
110
- }
111
-
112
116
  /** @protected */
113
117
  ready() {
114
118
  super.ready();