@vaadin/context-menu 24.8.4 → 25.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.
Files changed (44) hide show
  1. package/README.md +0 -23
  2. package/package.json +16 -17
  3. package/src/styles/vaadin-context-menu-item-base-styles.d.ts +8 -0
  4. package/src/styles/vaadin-context-menu-item-base-styles.js +34 -0
  5. package/src/styles/vaadin-context-menu-item-core-styles.d.ts +8 -0
  6. package/src/styles/vaadin-context-menu-item-core-styles.js +8 -0
  7. package/src/styles/vaadin-context-menu-overlay-base-styles.d.ts +8 -0
  8. package/src/styles/vaadin-context-menu-overlay-base-styles.js +9 -0
  9. package/src/styles/vaadin-context-menu-overlay-core-styles.d.ts +8 -0
  10. package/src/styles/vaadin-context-menu-overlay-core-styles.js +9 -0
  11. package/src/{vaadin-menu-overlay-styles.d.ts → styles/vaadin-menu-overlay-base-styles.d.ts} +1 -1
  12. package/src/styles/vaadin-menu-overlay-base-styles.js +31 -0
  13. package/src/styles/vaadin-menu-overlay-core-styles.d.ts +8 -0
  14. package/src/{vaadin-menu-overlay-styles.js → styles/vaadin-menu-overlay-core-styles.js} +1 -1
  15. package/src/vaadin-context-menu-item.js +11 -12
  16. package/src/vaadin-context-menu-list-box.d.ts +1 -2
  17. package/src/vaadin-context-menu-list-box.js +17 -26
  18. package/src/vaadin-context-menu-mixin.js +43 -70
  19. package/src/vaadin-context-menu-overlay.js +16 -11
  20. package/src/vaadin-context-menu.d.ts +15 -6
  21. package/src/vaadin-context-menu.js +44 -42
  22. package/src/vaadin-contextmenu-items-mixin.js +19 -15
  23. package/src/vaadin-menu-overlay-mixin.d.ts +0 -5
  24. package/src/vaadin-menu-overlay-mixin.js +22 -27
  25. package/web-types.json +6 -2
  26. package/web-types.lit.json +9 -2
  27. package/src/vaadin-lit-context-menu-item.js +0 -60
  28. package/src/vaadin-lit-context-menu-list-box.js +0 -87
  29. package/src/vaadin-lit-context-menu-overlay.js +0 -51
  30. package/src/vaadin-lit-context-menu.js +0 -79
  31. package/theme/lumo/vaadin-lit-context-menu.d.ts +0 -4
  32. package/theme/lumo/vaadin-lit-context-menu.js +0 -4
  33. package/theme/material/vaadin-context-menu-item-styles.d.ts +0 -5
  34. package/theme/material/vaadin-context-menu-item-styles.js +0 -36
  35. package/theme/material/vaadin-context-menu-list-box-styles.d.ts +0 -4
  36. package/theme/material/vaadin-context-menu-list-box-styles.js +0 -38
  37. package/theme/material/vaadin-context-menu-overlay-styles.d.ts +0 -2
  38. package/theme/material/vaadin-context-menu-overlay-styles.js +0 -15
  39. package/theme/material/vaadin-context-menu.d.ts +0 -4
  40. package/theme/material/vaadin-context-menu.js +0 -4
  41. package/theme/material/vaadin-lit-context-menu.d.ts +0 -4
  42. package/theme/material/vaadin-lit-context-menu.js +0 -4
  43. package/vaadin-lit-context-menu.d.ts +0 -1
  44. package/vaadin-lit-context-menu.js +0 -2
package/README.md CHANGED
@@ -50,29 +50,6 @@ Once installed, import the component in your application:
50
50
  import '@vaadin/context-menu';
51
51
  ```
52
52
 
53
- ## Themes
54
-
55
- Vaadin components come with two built-in [themes](https://vaadin.com/docs/latest/styling), Lumo and Material.
56
- The [main entrypoint](https://github.com/vaadin/web-components/blob/main/packages/context-menu/vaadin-context-menu.js) of the package uses the Lumo theme.
57
-
58
- To use the Material theme, import the component from the `theme/material` folder:
59
-
60
- ```js
61
- import '@vaadin/context-menu/theme/material/vaadin-context-menu.js';
62
- ```
63
-
64
- You can also import the Lumo version of the component explicitly:
65
-
66
- ```js
67
- import '@vaadin/context-menu/theme/lumo/vaadin-context-menu.js';
68
- ```
69
-
70
- Finally, you can import the un-themed component from the `src` folder to get a minimal starting point:
71
-
72
- ```js
73
- import '@vaadin/context-menu/src/vaadin-context-menu.js';
74
- ```
75
-
76
53
  ## License
77
54
 
78
55
  Apache License 2.0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/context-menu",
3
- "version": "24.8.4",
3
+ "version": "25.0.0-alpha10",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -23,6 +23,8 @@
23
23
  "lit.d.ts",
24
24
  "lit.js",
25
25
  "src",
26
+ "!src/styles/*-base-styles.d.ts",
27
+ "!src/styles/*-base-styles.js",
26
28
  "theme",
27
29
  "vaadin-*.d.ts",
28
30
  "vaadin-*.js",
@@ -33,32 +35,29 @@
33
35
  "Vaadin",
34
36
  "context menu",
35
37
  "web-components",
36
- "web-component",
37
- "polymer"
38
+ "web-component"
38
39
  ],
39
40
  "dependencies": {
40
41
  "@open-wc/dedupe-mixin": "^1.3.0",
41
- "@polymer/polymer": "^3.0.0",
42
- "@vaadin/a11y-base": "~24.8.4",
43
- "@vaadin/component-base": "~24.8.4",
44
- "@vaadin/item": "~24.8.4",
45
- "@vaadin/list-box": "~24.8.4",
46
- "@vaadin/lit-renderer": "~24.8.4",
47
- "@vaadin/overlay": "~24.8.4",
48
- "@vaadin/vaadin-lumo-styles": "~24.8.4",
49
- "@vaadin/vaadin-material-styles": "~24.8.4",
50
- "@vaadin/vaadin-themable-mixin": "~24.8.4",
42
+ "@vaadin/a11y-base": "25.0.0-alpha10",
43
+ "@vaadin/component-base": "25.0.0-alpha10",
44
+ "@vaadin/item": "25.0.0-alpha10",
45
+ "@vaadin/list-box": "25.0.0-alpha10",
46
+ "@vaadin/lit-renderer": "25.0.0-alpha10",
47
+ "@vaadin/overlay": "25.0.0-alpha10",
48
+ "@vaadin/vaadin-lumo-styles": "25.0.0-alpha10",
49
+ "@vaadin/vaadin-themable-mixin": "25.0.0-alpha10",
51
50
  "lit": "^3.0.0"
52
51
  },
53
52
  "devDependencies": {
54
- "@vaadin/chai-plugins": "~24.8.4",
55
- "@vaadin/test-runner-commands": "~24.8.4",
56
- "@vaadin/testing-helpers": "^1.1.0",
53
+ "@vaadin/chai-plugins": "25.0.0-alpha10",
54
+ "@vaadin/test-runner-commands": "25.0.0-alpha10",
55
+ "@vaadin/testing-helpers": "^2.0.0",
57
56
  "sinon": "^18.0.0"
58
57
  },
59
58
  "web-types": [
60
59
  "web-types.json",
61
60
  "web-types.lit.json"
62
61
  ],
63
- "gitHead": "849e54e967563080a685965e2dced02060b3ab23"
62
+ "gitHead": "6cc6c94079e805fa5b2f0af4dbf3b2a7485e57d0"
64
63
  }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2016 - 2025 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import type { CSSResult } from 'lit';
7
+
8
+ export const contextMenuItemStyles: CSSResult;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2016 - 2025 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import '@vaadin/component-base/src/style-props.js';
7
+ import { css } from 'lit';
8
+ import { itemStyles } from '@vaadin/item/src/styles/vaadin-item-base-styles.js';
9
+
10
+ const menuItemStyles = css`
11
+ :host::after {
12
+ background: var(--vaadin-color-subtle);
13
+ content: '';
14
+ display: block;
15
+ height: var(--vaadin-icon-size, 1lh);
16
+ mask-image: var(--_vaadin-icon-chevron-down);
17
+ rotate: -90deg;
18
+ visibility: hidden;
19
+ width: var(--vaadin-icon-size, 1lh);
20
+ }
21
+
22
+ :host([dir='rtl'])::after {
23
+ rotate: 90deg;
24
+ }
25
+
26
+ /* TODO would be nice to only reserve the space for these if
27
+ one or mote items in the list is checkable or has child items */
28
+ :host([aria-haspopup='true'])::after,
29
+ :host([menu-item-checked]) [part='checkmark'] {
30
+ visibility: visible;
31
+ }
32
+ `;
33
+
34
+ export const contextMenuItemStyles = [itemStyles, menuItemStyles];
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2016 - 2025 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import type { CSSResult } from 'lit';
7
+
8
+ export const contextMenuItemStyles: CSSResult;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2016 - 2025 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { itemStyles } from '@vaadin/item/src/styles/vaadin-item-core-styles.js';
7
+
8
+ export const contextMenuItemStyles = [itemStyles];
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2016 - 2025 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import type { CSSResult } from 'lit';
7
+
8
+ export const contextMenuOverlayStyles: CSSResult;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2016 - 2025 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { overlayStyles } from '@vaadin/overlay/src/styles/vaadin-overlay-base-styles.js';
7
+ import { menuOverlayStyles } from './vaadin-menu-overlay-base-styles.js';
8
+
9
+ export const contextMenuOverlayStyles = [overlayStyles, menuOverlayStyles];
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2016 - 2025 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import type { CSSResult } from 'lit';
7
+
8
+ export const contextMenuOverlayStyles: CSSResult;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2016 - 2025 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { overlayStyles } from '@vaadin/overlay/src/styles/vaadin-overlay-core-styles.js';
7
+ import { menuOverlayStyles } from './vaadin-menu-overlay-core-styles.js';
8
+
9
+ export const contextMenuOverlayStyles = [overlayStyles, menuOverlayStyles];
@@ -5,4 +5,4 @@
5
5
  */
6
6
  import type { CSSResult } from 'lit';
7
7
 
8
- export const styles: CSSResult;
8
+ export const menuOverlayStyles: CSSResult;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2016 - 2025 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { css } from 'lit';
7
+
8
+ export const menuOverlayStyles = css`
9
+ :host {
10
+ align-items: flex-start;
11
+ justify-content: flex-start;
12
+ }
13
+
14
+ :host([right-aligned]),
15
+ :host([end-aligned]) {
16
+ align-items: flex-end;
17
+ }
18
+
19
+ :host([bottom-aligned]) {
20
+ justify-content: flex-end;
21
+ }
22
+
23
+ [part='content'] {
24
+ padding: var(--vaadin-item-overlay-padding, 4px);
25
+ }
26
+
27
+ /* TODO keyboard focus becomes visible even when navigating the menu with the mouse */
28
+ [part='overlay']:focus-visible {
29
+ outline: none;
30
+ }
31
+ `;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2016 - 2025 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import type { CSSResult } from 'lit';
7
+
8
+ export const menuOverlayStyles: CSSResult;
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { css } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
7
7
 
8
- export const styles = css`
8
+ export const menuOverlayStyles = css`
9
9
  :host {
10
10
  align-items: flex-start;
11
11
  justify-content: flex-start;
@@ -3,11 +3,14 @@
3
3
  * Copyright (c) 2016 - 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 { ItemMixin } from '@vaadin/item/src/vaadin-item-mixin.js';
11
+ import { LumoInjectionMixin } from '@vaadin/vaadin-themable-mixin/lumo-injection-mixin.js';
10
12
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
13
+ import { contextMenuItemStyles } from './styles/vaadin-context-menu-item-core-styles.js';
11
14
 
12
15
  /**
13
16
  * An element used internally by `<vaadin-context-menu>`. Not intended to be used separately.
@@ -19,22 +22,18 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
19
22
  * @mixes ThemableMixin
20
23
  * @protected
21
24
  */
22
- class ContextMenuItem extends ItemMixin(ThemableMixin(DirMixin(PolymerElement))) {
25
+ class ContextMenuItem extends ItemMixin(ThemableMixin(DirMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
23
26
  static get is() {
24
27
  return 'vaadin-context-menu-item';
25
28
  }
26
29
 
27
- static get template() {
28
- return html`
29
- <style>
30
- :host {
31
- display: inline-block;
32
- }
30
+ static get styles() {
31
+ return contextMenuItemStyles;
32
+ }
33
33
 
34
- :host([hidden]) {
35
- display: none !important;
36
- }
37
- </style>
34
+ /** @protected */
35
+ render() {
36
+ return html`
38
37
  <span part="checkmark" aria-hidden="true"></span>
39
38
  <div part="content">
40
39
  <slot></slot>
@@ -4,14 +4,13 @@
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  import { ListMixin } from '@vaadin/a11y-base/src/list-mixin.js';
7
- import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
8
7
  import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
9
8
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
10
9
 
11
10
  /**
12
11
  * An element used internally by `<vaadin-context-menu>`. Not intended to be used separately.
13
12
  */
14
- declare class ContextMenuListBox extends ListMixin(DirMixin(ThemableMixin(ControllerMixin(HTMLElement)))) {}
13
+ declare class ContextMenuListBox extends ListMixin(DirMixin(ThemableMixin(HTMLElement))) {}
15
14
 
16
15
  declare global {
17
16
  interface HTMLElementTagNameMap {
@@ -3,11 +3,13 @@
3
3
  * Copyright (c) 2016 - 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 { ListMixin } from '@vaadin/a11y-base/src/list-mixin.js';
8
- import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
9
8
  import { defineCustomElement } from '@vaadin/component-base/src/define.js';
10
9
  import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
10
+ import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
11
+ import { listBoxStyles } from '@vaadin/list-box/src/styles/vaadin-list-box-core-styles.js';
12
+ import { LumoInjectionMixin } from '@vaadin/vaadin-themable-mixin/lumo-injection-mixin.js';
11
13
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
12
14
 
13
15
  /**
@@ -15,39 +17,18 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
15
17
  *
16
18
  * @customElement
17
19
  * @extends HTMLElement
18
- * @mixes ControllerMixin
19
20
  * @mixes DirMixin
20
21
  * @mixes ListMixin
21
22
  * @mixes ThemableMixin
22
23
  * @protected
23
24
  */
24
- class ContextMenuListBox extends ListMixin(ThemableMixin(DirMixin(ControllerMixin(PolymerElement)))) {
25
+ class ContextMenuListBox extends ListMixin(ThemableMixin(DirMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
25
26
  static get is() {
26
27
  return 'vaadin-context-menu-list-box';
27
28
  }
28
29
 
29
- static get template() {
30
- return html`
31
- <style>
32
- :host {
33
- display: flex;
34
- }
35
-
36
- :host([hidden]) {
37
- display: none !important;
38
- }
39
-
40
- [part='items'] {
41
- height: 100%;
42
- width: 100%;
43
- overflow-y: auto;
44
- -webkit-overflow-scrolling: touch;
45
- }
46
- </style>
47
- <div part="items">
48
- <slot></slot>
49
- </div>
50
- `;
30
+ static get styles() {
31
+ return listBoxStyles;
51
32
  }
52
33
 
53
34
  static get properties() {
@@ -56,6 +37,7 @@ class ContextMenuListBox extends ListMixin(ThemableMixin(DirMixin(ControllerMixi
56
37
  // but we don't want it to be modified, or be shown in the API docs.
57
38
  /** @private */
58
39
  orientation: {
40
+ type: String,
59
41
  readOnly: true,
60
42
  },
61
43
  };
@@ -70,6 +52,15 @@ class ContextMenuListBox extends ListMixin(ThemableMixin(DirMixin(ControllerMixi
70
52
  return this.shadowRoot.querySelector('[part="items"]');
71
53
  }
72
54
 
55
+ /** @protected */
56
+ render() {
57
+ return html`
58
+ <div part="items">
59
+ <slot></slot>
60
+ </div>
61
+ `;
62
+ }
63
+
73
64
  /** @protected */
74
65
  ready() {
75
66
  super.ready();
@@ -31,6 +31,8 @@ export const ContextMenuMixin = (superClass) =>
31
31
  */
32
32
  opened: {
33
33
  type: Boolean,
34
+ reflectToAttribute: true,
35
+ observer: '_openedChanged',
34
36
  value: false,
35
37
  notify: true,
36
38
  readOnly: true,
@@ -123,22 +125,15 @@ export const ContextMenuMixin = (superClass) =>
123
125
 
124
126
  static get observers() {
125
127
  return [
126
- '_openedChanged(opened)',
127
128
  '_targetOrOpenOnChanged(listenOn, openOn)',
128
129
  '_rendererChanged(renderer, items)',
129
130
  '_fullscreenChanged(_fullscreen)',
130
- '_overlayContextChanged(_overlayElement, _context)',
131
- '_overlayModelessChanged(_overlayElement, _modeless)',
132
- '_overlayPhoneChanged(_overlayElement, _phone)',
133
- '_overlayThemeChanged(_overlayElement, _theme)',
134
131
  ];
135
132
  }
136
133
 
137
134
  constructor() {
138
135
  super();
139
136
 
140
- this._createOverlay();
141
-
142
137
  this._boundOpen = this.open.bind(this);
143
138
  this._boundClose = this.close.bind(this);
144
139
  this._boundPreventDefault = this._preventDefault.bind(this);
@@ -170,8 +165,10 @@ export const ContextMenuMixin = (superClass) =>
170
165
  }
171
166
 
172
167
  /** @protected */
173
- ready() {
174
- super.ready();
168
+ firstUpdated() {
169
+ super.firstUpdated();
170
+
171
+ this._overlayElement = this.$.overlay;
175
172
 
176
173
  this.addController(
177
174
  new MediaQueryController(this._fullscreenMediaQuery, (matches) => {
@@ -180,29 +177,17 @@ export const ContextMenuMixin = (superClass) =>
180
177
  );
181
178
  }
182
179
 
183
- /** @private */
184
- _createOverlay() {
185
- // Create an overlay in the constructor to use in observers before `ready()`
186
- const overlay = document.createElement(`${this._tagNamePrefix}-overlay`);
187
- overlay.owner = this;
188
-
189
- overlay.addEventListener('opened-changed', (e) => {
190
- this._onOverlayOpened(e);
191
- });
192
-
193
- overlay.addEventListener('vaadin-overlay-open', (e) => {
194
- this._onVaadinOverlayOpen(e);
195
- });
196
-
197
- this._overlayElement = overlay;
198
- }
199
-
200
180
  /**
201
181
  * Runs before overlay is fully rendered
202
182
  * @private
203
183
  */
204
- _onOverlayOpened(e) {
205
- const opened = e.detail.value;
184
+ _onOverlayOpened(event) {
185
+ // Ignore events from submenus
186
+ if (event.target !== this._overlayElement) {
187
+ return;
188
+ }
189
+
190
+ const opened = event.detail.value;
206
191
  this._setOpened(opened);
207
192
  if (opened) {
208
193
  this.__alignOverlayPosition();
@@ -213,43 +198,23 @@ export const ContextMenuMixin = (superClass) =>
213
198
  * Runs after overlay is fully rendered
214
199
  * @private
215
200
  */
216
- _onVaadinOverlayOpen() {
201
+ _onVaadinOverlayOpen(event) {
202
+ // Ignore events from submenus
203
+ if (event.target !== this._overlayElement) {
204
+ return;
205
+ }
206
+
217
207
  this.__alignOverlayPosition();
218
208
  this._overlayElement.style.visibility = '';
219
209
  this.__forwardFocus();
220
210
  }
221
211
 
222
- /** @private */
223
- _overlayContextChanged(overlay, context) {
224
- if (overlay) {
225
- overlay.model = context;
226
- }
227
- }
228
-
229
- /** @private */
230
- _overlayModelessChanged(overlay, modeless) {
231
- if (overlay) {
232
- overlay.modeless = modeless;
233
- }
234
- }
235
-
236
- /** @private */
237
- _overlayPhoneChanged(overlay, phone) {
238
- if (overlay) {
239
- overlay.toggleAttribute('phone', phone);
240
- overlay.withBackdrop = phone;
241
- }
242
- }
243
-
244
- /** @private */
245
- _overlayThemeChanged(overlay, theme) {
246
- if (overlay) {
247
- if (theme) {
248
- overlay.setAttribute('theme', theme);
249
- } else {
250
- overlay.removeAttribute('theme');
251
- }
252
- }
212
+ /**
213
+ * Runs after overlay's closing animation is finished
214
+ * @private
215
+ */
216
+ _onVaadinOverlayClosed() {
217
+ this.dispatchEvent(new CustomEvent('closed'));
253
218
  }
254
219
 
255
220
  /** @private */
@@ -318,17 +283,14 @@ export const ContextMenuMixin = (superClass) =>
318
283
  }
319
284
 
320
285
  /** @private */
321
- _openedChanged(opened) {
286
+ _openedChanged(opened, oldOpened) {
322
287
  if (opened) {
323
288
  document.documentElement.addEventListener('contextmenu', this._boundOnGlobalContextMenu, true);
324
- } else {
289
+ } else if (oldOpened) {
325
290
  document.documentElement.removeEventListener('contextmenu', this._boundOnGlobalContextMenu, true);
326
291
  }
327
292
 
328
293
  this.__setListenOnUserSelect(opened);
329
-
330
- // Has to be set after instance has been created
331
- this._overlayElement.opened = opened;
332
294
  }
333
295
 
334
296
  /**
@@ -362,11 +324,7 @@ export const ContextMenuMixin = (superClass) =>
362
324
  if (this.closeOn === 'click') {
363
325
  this.closeOn = '';
364
326
  }
365
-
366
- renderer = this.__itemsRenderer;
367
327
  }
368
-
369
- this._overlayElement.renderer = renderer;
370
328
  }
371
329
 
372
330
  /**
@@ -393,6 +351,11 @@ export const ContextMenuMixin = (superClass) =>
393
351
  * @param {!Event | undefined} e used as the context for the menu. Overlay coordinates are taken from this event.
394
352
  */
395
353
  open(e) {
354
+ // Ignore events from the overlay
355
+ if (this._overlayElement && e.composedPath().includes(this._overlayElement)) {
356
+ return;
357
+ }
358
+
396
359
  if (e && !this.opened) {
397
360
  this._context = {
398
361
  detail: e.detail,
@@ -671,7 +634,11 @@ export const ContextMenuMixin = (superClass) =>
671
634
  // Dispatch another contextmenu at the same coordinates after the overlay is closed
672
635
  this._overlayElement.addEventListener(
673
636
  'vaadin-overlay-closed',
674
- () => this.__contextMenuAt(e.clientX, e.clientY),
637
+ (closeEvent) => {
638
+ if (closeEvent.target === this._overlayElement) {
639
+ this.__contextMenuAt(e.clientX, e.clientY);
640
+ }
641
+ },
675
642
  {
676
643
  once: true,
677
644
  },
@@ -682,4 +649,10 @@ export const ContextMenuMixin = (superClass) =>
682
649
  this.close();
683
650
  }
684
651
  }
652
+
653
+ /**
654
+ * Fired when the context menu is closed.
655
+ *
656
+ * @event closed
657
+ */
685
658
  };
@@ -3,18 +3,15 @@
3
3
  * Copyright (c) 2016 - 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 { OverlayMixin } from '@vaadin/overlay/src/vaadin-overlay-mixin.js';
10
- import { overlayStyles } from '@vaadin/overlay/src/vaadin-overlay-styles.js';
11
- import { registerStyles, ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
11
+ import { LumoInjectionMixin } from '@vaadin/vaadin-themable-mixin/lumo-injection-mixin.js';
12
+ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
13
+ import { contextMenuOverlayStyles } from './styles/vaadin-context-menu-overlay-core-styles.js';
12
14
  import { MenuOverlayMixin } from './vaadin-menu-overlay-mixin.js';
13
- import { styles } from './vaadin-menu-overlay-styles.js';
14
-
15
- registerStyles('vaadin-context-menu-overlay', [overlayStyles, styles], {
16
- moduleId: 'vaadin-context-menu-overlay-styles',
17
- });
18
15
 
19
16
  /**
20
17
  * An element used internally by `<vaadin-context-menu>`. Not intended to be used separately.
@@ -27,17 +24,25 @@ registerStyles('vaadin-context-menu-overlay', [overlayStyles, styles], {
27
24
  * @mixes ThemableMixin
28
25
  * @protected
29
26
  */
30
- export class ContextMenuOverlay extends MenuOverlayMixin(OverlayMixin(DirMixin(ThemableMixin(PolymerElement)))) {
27
+ export class ContextMenuOverlay extends MenuOverlayMixin(
28
+ OverlayMixin(DirMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))),
29
+ ) {
31
30
  static get is() {
32
31
  return 'vaadin-context-menu-overlay';
33
32
  }
34
33
 
35
- static get template() {
34
+ static get styles() {
35
+ return contextMenuOverlayStyles;
36
+ }
37
+
38
+ /** @protected */
39
+ render() {
36
40
  return html`
37
- <div id="backdrop" part="backdrop" hidden$="[[!withBackdrop]]"></div>
41
+ <div id="backdrop" part="backdrop" ?hidden="${!this.withBackdrop}"></div>
38
42
  <div part="overlay" id="overlay" tabindex="0">
39
43
  <div part="content" id="content">
40
44
  <slot></slot>
45
+ <slot name="submenu"></slot>
41
46
  </div>
42
47
  </div>
43
48
  `;