Skip to content

Commit

Permalink
experiment: add LitElement based version of menu-bar
Browse files Browse the repository at this point in the history
  • Loading branch information
web-padawan committed Jan 12, 2024
1 parent 7dec842 commit abb71e8
Show file tree
Hide file tree
Showing 23 changed files with 575 additions and 59 deletions.
5 changes: 4 additions & 1 deletion packages/menu-bar/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
"theme",
"vaadin-*.d.ts",
"vaadin-*.js",
"!vaadin-lit-*.d.ts",
"!vaadin-lit-*.js",
"web-types.json",
"web-types.lit.json"
],
Expand All @@ -46,7 +48,8 @@
"@vaadin/overlay": "24.4.0-alpha3",
"@vaadin/vaadin-lumo-styles": "24.4.0-alpha3",
"@vaadin/vaadin-material-styles": "24.4.0-alpha3",
"@vaadin/vaadin-themable-mixin": "24.4.0-alpha3"
"@vaadin/vaadin-themable-mixin": "24.4.0-alpha3",
"lit": "^3.0.0"
},
"devDependencies": {
"@esm-bundle/chai": "^4.3.4",
Expand Down
43 changes: 43 additions & 0 deletions packages/menu-bar/src/vaadin-lit-menu-bar-button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* @license
* Copyright (c) 2019 - 2023 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import { Button } from '@vaadin/button/src/vaadin-lit-button.js';
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
import { css } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';

/**
* An element used internally by `<vaadin-menu-bar>`. Not intended to be used separately.
*
* @customElement
* @extends Button
* @private
*/
class MenuBarButton extends Button {
static get is() {
return 'vaadin-menu-bar-button';
}

static get styles() {
return [
super.styles,
css`
:host {
flex-shrink: 0;
}
:host([slot='overflow']) {
margin-inline-end: 0;
}
[part='label'] ::slotted(vaadin-menu-bar-item) {
position: relative;
z-index: 1;
}
`,
];
}
}

defineCustomElement(MenuBarButton);
62 changes: 62 additions & 0 deletions packages/menu-bar/src/vaadin-lit-menu-bar-item.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* @license
* Copyright (c) 2019 - 2023 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import { css, html, LitElement } from 'lit';
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
import { ItemMixin } from '@vaadin/item/src/vaadin-item-mixin.js';
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';

/**
* An element used internally by `<vaadin-menu-bar>`. Not intended to be used separately.
*
* @customElement
* @extends HTMLElement
* @mixes DirMixin
* @mixes ItemMixin
* @mixes ThemableMixin
* @protected
*/
class MenuBarItem extends ItemMixin(ThemableMixin(DirMixin(PolylitMixin(LitElement)))) {
static get is() {
return 'vaadin-menu-bar-item';
}

static get styles() {
return css`
:host {
display: inline-block;
}
:host([hidden]) {
display: none !important;
}
`;
}

/** @protected */
render() {
return html`
<span part="checkmark" aria-hidden="true"></span>
<div part="content">
<slot></slot>
</div>
`;
}

/** @protected */
connectedCallback() {
super.connectedCallback();

// Set role in `connectedCallback()` instead of `ready()`
// because the role is removed when teleporting to button.
this.setAttribute('role', 'menuitem');
}
}

defineCustomElement(MenuBarItem);

export { MenuBarItem };
87 changes: 87 additions & 0 deletions packages/menu-bar/src/vaadin-lit-menu-bar-list-box.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
* @license
* Copyright (c) 2019 - 2023 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import { css, html, LitElement } from 'lit';
import { ListMixin } from '@vaadin/a11y-base/src/list-mixin.js';
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';

/**
* An element used internally by `<vaadin-menu-bar>`. Not intended to be used separately.
*
* @customElement
* @extends HTMLElement
* @mixes DirMixin
* @mixes ListMixin
* @mixes ThemableMixin
* @protected
*/
class MenuBarListBox extends ListMixin(ThemableMixin(DirMixin(PolylitMixin(LitElement)))) {
static get is() {
return 'vaadin-menu-bar-list-box';
}

static get styles() {
return css`
:host {
display: flex;
}
:host([hidden]) {
display: none !important;
}
[part='items'] {
height: 100%;
width: 100%;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
`;
}

static get properties() {
return {
// We don't need to define this property since super default is vertical,
// but we don't want it to be modified, or be shown in the API docs.
/** @private */
orientation: {
type: String,
readOnly: true,
},
};
}

/**
* @return {!HTMLElement}
* @protected
* @override
*/
get _scrollerElement() {
return this.shadowRoot.querySelector('[part="items"]');
}

/** @protected */
render() {
return html`
<div part="items">
<slot></slot>
</div>
`;
}

/** @protected */
ready() {
super.ready();

this.setAttribute('role', 'menu');
}
}

defineCustomElement(MenuBarListBox);

export { MenuBarListBox };
65 changes: 65 additions & 0 deletions packages/menu-bar/src/vaadin-lit-menu-bar-overlay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* @license
* Copyright (c) 2016 - 2023 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import { html, LitElement } from 'lit';
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
import { MenuOverlayMixin } from '@vaadin/context-menu/src/vaadin-menu-overlay-mixin.js';
import { styles } from '@vaadin/context-menu/src/vaadin-menu-overlay-styles.js';
import { OverlayMixin } from '@vaadin/overlay/src/vaadin-overlay-mixin.js';
import { overlayStyles } from '@vaadin/overlay/src/vaadin-overlay-styles.js';
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';

/**
* An element used internally by `<vaadin-menu-bar>`. Not intended to be used separately.
*
* @customElement
* @extends HTMLElement
* @mixes DirMixin
* @mixes MenuOverlayMixin
* @mixes OverlayMixin
* @mixes ThemableMixin
* @protected
*/
export class MenuBarOverlay extends MenuOverlayMixin(OverlayMixin(DirMixin(ThemableMixin(PolylitMixin(LitElement))))) {
static get is() {
return 'vaadin-menu-bar-overlay';
}

static get properties() {
return {
/**
* When true, the overlay is visible and attached to body.
* This property config is overridden to set `sync: true`.
*/
opened: {
type: Boolean,
notify: true,
observer: '_openedChanged',
reflectToAttribute: true,
sync: true,
},
};
}

static get styles() {
return [overlayStyles, styles];
}

/** @protected */
render() {
return html`
<div id="backdrop" part="backdrop" ?hidden="${!this.withBackdrop}"></div>
<div part="overlay" id="overlay" tabindex="0">
<div part="content" id="content">
<slot></slot>
</div>
</div>
`;
}
}

defineCustomElement(MenuBarOverlay);
93 changes: 93 additions & 0 deletions packages/menu-bar/src/vaadin-lit-menu-bar-submenu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/**
* @license
* Copyright (c) 2019 - 2023 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import './vaadin-lit-menu-bar-item.js';
import './vaadin-lit-menu-bar-list-box.js';
import './vaadin-lit-menu-bar-overlay.js';
import { css, html, LitElement } from 'lit';
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
import { OverlayClassMixin } from '@vaadin/component-base/src/overlay-class-mixin.js';
import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
import { ContextMenuMixin } from '@vaadin/context-menu/src/vaadin-context-menu-mixin.js';
import { ThemePropertyMixin } from '@vaadin/vaadin-themable-mixin/vaadin-theme-property-mixin.js';

/**
* An element used internally by `<vaadin-menu-bar>`. Not intended to be used separately.
*
* @customElement
* @extends HTMLElement
* @mixes ContextMenuMixin
* @mixes OverlayClassMixin
* @mixes ThemePropertyMixin
* @protected
*/
class MenuBarSubmenu extends ContextMenuMixin(OverlayClassMixin(ThemePropertyMixin(PolylitMixin(LitElement)))) {
static get is() {
return 'vaadin-menu-bar-submenu';
}

static get styles() {
return css`
:host {
display: block;
}
:host([hidden]) {
display: none !important;
}
`;
}

constructor() {
super();

this.openOn = 'opensubmenu';
}

/**
* Tag name prefix used by overlay, list-box and items.
* @protected
* @return {string}
*/
get _tagNamePrefix() {
return 'vaadin-menu-bar';
}

/** @protected */
render() {
return html`<slot id="slot"></slot>`;
}

/**
* @protected
* @override
*/
createRenderRoot() {
const root = super.createRenderRoot();
root.appendChild(this._overlayElement);
return root;
}

/**
* Overriding the observer to not add global "contextmenu" listener.
*/
_openedChanged(opened) {
this._overlayElement.opened = opened;
}

/**
* Overriding the public method to reset expanded button state.
*/
close() {
super.close();

// Only handle 1st level submenu
if (this.hasAttribute('is-root')) {
this.getRootNode().host._close();
}
}
}

defineCustomElement(MenuBarSubmenu);
Loading

0 comments on commit abb71e8

Please sign in to comment.