@vaadin/context-menu 25.0.0-alpha8 → 25.0.0-beta1
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 +13 -16
- package/src/styles/vaadin-context-menu-item-base-styles.js +3 -3
- package/src/styles/vaadin-context-menu-overlay-base-styles.js +28 -1
- package/src/vaadin-context-menu-item.js +1 -1
- package/src/vaadin-context-menu-list-box.js +1 -1
- package/src/vaadin-context-menu-mixin.js +48 -76
- package/src/vaadin-context-menu-overlay.js +56 -1
- package/src/vaadin-context-menu.d.ts +48 -11
- package/src/vaadin-context-menu.js +98 -23
- package/src/vaadin-contextmenu-items-mixin.js +44 -30
- package/src/vaadin-menu-overlay-mixin.d.ts +0 -5
- package/src/vaadin-menu-overlay-mixin.js +23 -28
- package/vaadin-context-menu.js +1 -1
- package/web-types.json +10 -6
- package/web-types.lit.json +11 -4
- package/src/styles/vaadin-context-menu-item-core-styles.d.ts +0 -8
- package/src/styles/vaadin-context-menu-item-core-styles.js +0 -8
- package/src/styles/vaadin-context-menu-overlay-core-styles.d.ts +0 -8
- package/src/styles/vaadin-context-menu-overlay-core-styles.js +0 -9
- package/src/styles/vaadin-menu-overlay-core-styles.d.ts +0 -8
- package/src/styles/vaadin-menu-overlay-core-styles.js +0 -32
- package/theme/lumo/vaadin-context-menu-item-styles.d.ts +0 -6
- package/theme/lumo/vaadin-context-menu-item-styles.js +0 -45
- package/theme/lumo/vaadin-context-menu-list-box-styles.d.ts +0 -5
- package/theme/lumo/vaadin-context-menu-list-box-styles.js +0 -47
- package/theme/lumo/vaadin-context-menu-overlay-styles.d.ts +0 -4
- package/theme/lumo/vaadin-context-menu-overlay-styles.js +0 -35
- package/theme/lumo/vaadin-context-menu.d.ts +0 -4
- package/theme/lumo/vaadin-context-menu.js +0 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/context-menu",
|
|
3
|
-
"version": "25.0.0-
|
|
3
|
+
"version": "25.0.0-beta1",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -23,9 +23,6 @@
|
|
|
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",
|
|
28
|
-
"theme",
|
|
29
26
|
"vaadin-*.d.ts",
|
|
30
27
|
"vaadin-*.js",
|
|
31
28
|
"web-types.json",
|
|
@@ -39,25 +36,25 @@
|
|
|
39
36
|
],
|
|
40
37
|
"dependencies": {
|
|
41
38
|
"@open-wc/dedupe-mixin": "^1.3.0",
|
|
42
|
-
"@vaadin/a11y-base": "25.0.0-
|
|
43
|
-
"@vaadin/component-base": "25.0.0-
|
|
44
|
-
"@vaadin/item": "25.0.0-
|
|
45
|
-
"@vaadin/list-box": "25.0.0-
|
|
46
|
-
"@vaadin/lit-renderer": "25.0.0-
|
|
47
|
-
"@vaadin/overlay": "25.0.0-
|
|
48
|
-
"@vaadin/vaadin-
|
|
49
|
-
"@vaadin/vaadin-themable-mixin": "25.0.0-alpha8",
|
|
39
|
+
"@vaadin/a11y-base": "25.0.0-beta1",
|
|
40
|
+
"@vaadin/component-base": "25.0.0-beta1",
|
|
41
|
+
"@vaadin/item": "25.0.0-beta1",
|
|
42
|
+
"@vaadin/list-box": "25.0.0-beta1",
|
|
43
|
+
"@vaadin/lit-renderer": "25.0.0-beta1",
|
|
44
|
+
"@vaadin/overlay": "25.0.0-beta1",
|
|
45
|
+
"@vaadin/vaadin-themable-mixin": "25.0.0-beta1",
|
|
50
46
|
"lit": "^3.0.0"
|
|
51
47
|
},
|
|
52
48
|
"devDependencies": {
|
|
53
|
-
"@vaadin/chai-plugins": "25.0.0-
|
|
54
|
-
"@vaadin/test-runner-commands": "25.0.0-
|
|
49
|
+
"@vaadin/chai-plugins": "25.0.0-beta1",
|
|
50
|
+
"@vaadin/test-runner-commands": "25.0.0-beta1",
|
|
55
51
|
"@vaadin/testing-helpers": "^2.0.0",
|
|
56
|
-
"
|
|
52
|
+
"@vaadin/vaadin-lumo-styles": "25.0.0-beta1",
|
|
53
|
+
"sinon": "^21.0.0"
|
|
57
54
|
},
|
|
58
55
|
"web-types": [
|
|
59
56
|
"web-types.json",
|
|
60
57
|
"web-types.lit.json"
|
|
61
58
|
],
|
|
62
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "1d20cf54e582d1f2e209126d4586f8b4c01c50e0"
|
|
63
60
|
}
|
|
@@ -3,17 +3,17 @@
|
|
|
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 '@vaadin/component-base/src/style-props.js';
|
|
6
|
+
import '@vaadin/component-base/src/styles/style-props.js';
|
|
7
7
|
import { css } from 'lit';
|
|
8
8
|
import { itemStyles } from '@vaadin/item/src/styles/vaadin-item-base-styles.js';
|
|
9
9
|
|
|
10
10
|
const menuItemStyles = css`
|
|
11
11
|
:host::after {
|
|
12
|
-
background: var(--vaadin-color-
|
|
12
|
+
background: var(--vaadin-text-color-secondary);
|
|
13
13
|
content: '';
|
|
14
14
|
display: block;
|
|
15
15
|
height: var(--vaadin-icon-size, 1lh);
|
|
16
|
-
mask
|
|
16
|
+
mask: var(--_vaadin-icon-chevron-down) 50% / var(--vaadin-icon-visual-size, 100%) no-repeat;
|
|
17
17
|
rotate: -90deg;
|
|
18
18
|
visibility: hidden;
|
|
19
19
|
width: var(--vaadin-icon-size, 1lh);
|
|
@@ -3,7 +3,34 @@
|
|
|
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 { css } from 'lit';
|
|
6
7
|
import { overlayStyles } from '@vaadin/overlay/src/styles/vaadin-overlay-base-styles.js';
|
|
7
8
|
import { menuOverlayStyles } from './vaadin-menu-overlay-base-styles.js';
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
const contextMenuOverlay = css`
|
|
11
|
+
:host {
|
|
12
|
+
--_default-offset: 4px;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
:host([position^='top'][top-aligned]) [part='overlay'],
|
|
16
|
+
:host([position^='bottom'][top-aligned]) [part='overlay'] {
|
|
17
|
+
margin-top: var(--vaadin-context-menu-offset-top, var(--_default-offset));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
:host([position^='top'][bottom-aligned]) [part='overlay'],
|
|
21
|
+
:host([position^='bottom'][bottom-aligned]) [part='overlay'] {
|
|
22
|
+
margin-bottom: var(--vaadin-context-menu-offset-bottom, var(--_default-offset));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
:host([position^='start'][start-aligned]) [part='overlay'],
|
|
26
|
+
:host([position^='end'][start-aligned]) [part='overlay'] {
|
|
27
|
+
margin-inline-start: var(--vaadin-context-menu-offset-start, var(--_default-offset));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
:host([position^='start'][end-aligned]) [part='overlay'],
|
|
31
|
+
:host([position^='end'][end-aligned]) [part='overlay'] {
|
|
32
|
+
margin-inline-end: var(--vaadin-context-menu-offset-end, var(--_default-offset));
|
|
33
|
+
}
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
export const contextMenuOverlayStyles = [overlayStyles, menuOverlayStyles, contextMenuOverlay];
|
|
@@ -10,7 +10,7 @@ import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
|
|
|
10
10
|
import { ItemMixin } from '@vaadin/item/src/vaadin-item-mixin.js';
|
|
11
11
|
import { LumoInjectionMixin } from '@vaadin/vaadin-themable-mixin/lumo-injection-mixin.js';
|
|
12
12
|
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
13
|
-
import { contextMenuItemStyles } from './styles/vaadin-context-menu-item-
|
|
13
|
+
import { contextMenuItemStyles } from './styles/vaadin-context-menu-item-base-styles.js';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* An element used internally by `<vaadin-context-menu>`. Not intended to be used separately.
|
|
@@ -8,7 +8,7 @@ import { ListMixin } from '@vaadin/a11y-base/src/list-mixin.js';
|
|
|
8
8
|
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
|
|
9
9
|
import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
|
|
10
10
|
import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
|
|
11
|
-
import { listBoxStyles } from '@vaadin/list-box/src/styles/vaadin-list-box-
|
|
11
|
+
import { listBoxStyles } from '@vaadin/list-box/src/styles/vaadin-list-box-base-styles.js';
|
|
12
12
|
import { LumoInjectionMixin } from '@vaadin/vaadin-themable-mixin/lumo-injection-mixin.js';
|
|
13
13
|
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
14
14
|
|
|
@@ -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
|
-
|
|
174
|
-
super.
|
|
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(
|
|
205
|
-
|
|
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
|
-
/**
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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
|
/**
|
|
@@ -384,6 +342,9 @@ export const ContextMenuMixin = (superClass) =>
|
|
|
384
342
|
return Array.prototype.filter.call(targets, (el) => {
|
|
385
343
|
return e.composedPath().indexOf(el) > -1;
|
|
386
344
|
})[0];
|
|
345
|
+
} else if (this.listenOn && this.listenOn !== this && this.position) {
|
|
346
|
+
// If listenOn has been set on a different element than the context menu root, then use listenOn as the target.
|
|
347
|
+
return this.listenOn;
|
|
387
348
|
}
|
|
388
349
|
return e.target;
|
|
389
350
|
}
|
|
@@ -393,6 +354,11 @@ export const ContextMenuMixin = (superClass) =>
|
|
|
393
354
|
* @param {!Event | undefined} e used as the context for the menu. Overlay coordinates are taken from this event.
|
|
394
355
|
*/
|
|
395
356
|
open(e) {
|
|
357
|
+
// Ignore events from the overlay
|
|
358
|
+
if (this._overlayElement && e.composedPath().includes(this._overlayElement)) {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
|
|
396
362
|
if (e && !this.opened) {
|
|
397
363
|
this._context = {
|
|
398
364
|
detail: e.detail,
|
|
@@ -472,17 +438,13 @@ export const ContextMenuMixin = (superClass) =>
|
|
|
472
438
|
/** @private */
|
|
473
439
|
__focusItem(item) {
|
|
474
440
|
if (item) {
|
|
475
|
-
item.focus();
|
|
476
|
-
|
|
477
|
-
if (isKeyboardActive()) {
|
|
478
|
-
item.setAttribute('focus-ring', '');
|
|
479
|
-
}
|
|
441
|
+
item.focus({ focusVisible: isKeyboardActive() });
|
|
480
442
|
}
|
|
481
443
|
}
|
|
482
444
|
|
|
483
445
|
/** @private */
|
|
484
446
|
__onScroll() {
|
|
485
|
-
if (!this.opened) {
|
|
447
|
+
if (!this.opened || this.position) {
|
|
486
448
|
return;
|
|
487
449
|
}
|
|
488
450
|
|
|
@@ -671,7 +633,11 @@ export const ContextMenuMixin = (superClass) =>
|
|
|
671
633
|
// Dispatch another contextmenu at the same coordinates after the overlay is closed
|
|
672
634
|
this._overlayElement.addEventListener(
|
|
673
635
|
'vaadin-overlay-closed',
|
|
674
|
-
() =>
|
|
636
|
+
(closeEvent) => {
|
|
637
|
+
if (closeEvent.target === this._overlayElement) {
|
|
638
|
+
this.__contextMenuAt(e.clientX, e.clientY);
|
|
639
|
+
}
|
|
640
|
+
},
|
|
675
641
|
{
|
|
676
642
|
once: true,
|
|
677
643
|
},
|
|
@@ -682,4 +648,10 @@ export const ContextMenuMixin = (superClass) =>
|
|
|
682
648
|
this.close();
|
|
683
649
|
}
|
|
684
650
|
}
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Fired when the context menu is closed.
|
|
654
|
+
*
|
|
655
|
+
* @event closed
|
|
656
|
+
*/
|
|
685
657
|
};
|
|
@@ -10,7 +10,7 @@ import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
|
|
|
10
10
|
import { OverlayMixin } from '@vaadin/overlay/src/vaadin-overlay-mixin.js';
|
|
11
11
|
import { LumoInjectionMixin } from '@vaadin/vaadin-themable-mixin/lumo-injection-mixin.js';
|
|
12
12
|
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
13
|
-
import { contextMenuOverlayStyles } from './styles/vaadin-context-menu-overlay-
|
|
13
|
+
import { contextMenuOverlayStyles } from './styles/vaadin-context-menu-overlay-base-styles.js';
|
|
14
14
|
import { MenuOverlayMixin } from './vaadin-menu-overlay-mixin.js';
|
|
15
15
|
|
|
16
16
|
/**
|
|
@@ -31,10 +31,64 @@ export class ContextMenuOverlay extends MenuOverlayMixin(
|
|
|
31
31
|
return 'vaadin-context-menu-overlay';
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
static get properties() {
|
|
35
|
+
return {
|
|
36
|
+
/**
|
|
37
|
+
* Position of the overlay with respect to the target.
|
|
38
|
+
* Supported values: null, `top-start`, `top`, `top-end`,
|
|
39
|
+
* `bottom-start`, `bottom`, `bottom-end`, `start-top`,
|
|
40
|
+
* `start`, `start-bottom`, `end-top`, `end`, `end-bottom`.
|
|
41
|
+
*/
|
|
42
|
+
position: {
|
|
43
|
+
type: String,
|
|
44
|
+
reflectToAttribute: true,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
34
49
|
static get styles() {
|
|
35
50
|
return contextMenuOverlayStyles;
|
|
36
51
|
}
|
|
37
52
|
|
|
53
|
+
/**
|
|
54
|
+
* @protected
|
|
55
|
+
* @override
|
|
56
|
+
*/
|
|
57
|
+
_updatePosition() {
|
|
58
|
+
super._updatePosition();
|
|
59
|
+
|
|
60
|
+
if (this.parentOverlay == null && this.positionTarget && this.position && this.opened) {
|
|
61
|
+
if (this.position === 'bottom' || this.position === 'top') {
|
|
62
|
+
const targetRect = this.positionTarget.getBoundingClientRect();
|
|
63
|
+
const overlayRect = this.$.overlay.getBoundingClientRect();
|
|
64
|
+
|
|
65
|
+
const offset = targetRect.width / 2 - overlayRect.width / 2;
|
|
66
|
+
|
|
67
|
+
if (this.style.left) {
|
|
68
|
+
const left = overlayRect.left + offset;
|
|
69
|
+
if (left > 0) {
|
|
70
|
+
this.style.left = `${left}px`;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (this.style.right) {
|
|
75
|
+
const right = parseFloat(this.style.right) + offset;
|
|
76
|
+
if (right > 0) {
|
|
77
|
+
this.style.right = `${right}px`;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (this.position === 'start' || this.position === 'end') {
|
|
83
|
+
const targetRect = this.positionTarget.getBoundingClientRect();
|
|
84
|
+
const overlayRect = this.$.overlay.getBoundingClientRect();
|
|
85
|
+
|
|
86
|
+
const offset = targetRect.height / 2 - overlayRect.height / 2;
|
|
87
|
+
this.style.top = `${overlayRect.top + offset}px`;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
38
92
|
/** @protected */
|
|
39
93
|
render() {
|
|
40
94
|
return html`
|
|
@@ -42,6 +96,7 @@ export class ContextMenuOverlay extends MenuOverlayMixin(
|
|
|
42
96
|
<div part="overlay" id="overlay" tabindex="0">
|
|
43
97
|
<div part="content" id="content">
|
|
44
98
|
<slot></slot>
|
|
99
|
+
<slot name="submenu"></slot>
|
|
45
100
|
</div>
|
|
46
101
|
</div>
|
|
47
102
|
`;
|
|
@@ -4,13 +4,26 @@
|
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
6
|
import type { ElementMixinClass } from '@vaadin/component-base/src/element-mixin.js';
|
|
7
|
-
import type { OverlayClassMixinClass } from '@vaadin/component-base/src/overlay-class-mixin.js';
|
|
8
7
|
import type { ThemePropertyMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-theme-property-mixin.js';
|
|
9
8
|
import type { ContextMenuMixinClass } from './vaadin-context-menu-mixin.js';
|
|
10
9
|
import type { ContextMenuItem } from './vaadin-contextmenu-items-mixin.js';
|
|
11
10
|
|
|
12
11
|
export { ContextMenuItem };
|
|
13
12
|
|
|
13
|
+
export type ContextMenuPosition =
|
|
14
|
+
| 'bottom-end'
|
|
15
|
+
| 'bottom-start'
|
|
16
|
+
| 'bottom'
|
|
17
|
+
| 'end-bottom'
|
|
18
|
+
| 'end-top'
|
|
19
|
+
| 'end'
|
|
20
|
+
| 'start-bottom'
|
|
21
|
+
| 'start-top'
|
|
22
|
+
| 'start'
|
|
23
|
+
| 'top-end'
|
|
24
|
+
| 'top-start'
|
|
25
|
+
| 'top';
|
|
26
|
+
|
|
14
27
|
export interface ContextMenuRendererContext {
|
|
15
28
|
target: HTMLElement;
|
|
16
29
|
detail?: { sourceEvent: Event };
|
|
@@ -34,6 +47,11 @@ export type ContextMenuItemSelectedEvent<TItem extends ContextMenuItem = Context
|
|
|
34
47
|
value: TItem;
|
|
35
48
|
}>;
|
|
36
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Fired when the context menu is closed.
|
|
52
|
+
*/
|
|
53
|
+
export type ContextMenuClosedEvent = CustomEvent;
|
|
54
|
+
|
|
37
55
|
export interface ContextMenuCustomEventMap<TItem extends ContextMenuItem = ContextMenuItem> {
|
|
38
56
|
'opened-changed': ContextMenuOpenedChangedEvent;
|
|
39
57
|
|
|
@@ -42,6 +60,8 @@ export interface ContextMenuCustomEventMap<TItem extends ContextMenuItem = Conte
|
|
|
42
60
|
'close-all-menus': Event;
|
|
43
61
|
|
|
44
62
|
'items-outside-click': Event;
|
|
63
|
+
|
|
64
|
+
closed: ContextMenuClosedEvent;
|
|
45
65
|
}
|
|
46
66
|
|
|
47
67
|
export interface ContextMenuEventMap<TItem extends ContextMenuItem = ContextMenuItem>
|
|
@@ -208,18 +228,30 @@ export interface ContextMenuEventMap<TItem extends ContextMenuItem = ContextMenu
|
|
|
208
228
|
*
|
|
209
229
|
* ### Styling
|
|
210
230
|
*
|
|
211
|
-
*
|
|
212
|
-
* themable component as the actual visible context menu overlay.
|
|
231
|
+
* The following shadow DOM parts are available for styling:
|
|
213
232
|
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
233
|
+
* Part name | Description
|
|
234
|
+
* -----------------|-------------------------------------------
|
|
235
|
+
* `backdrop` | Backdrop of the overlay
|
|
236
|
+
* `overlay` | The overlay container
|
|
237
|
+
* `content` | The overlay content
|
|
238
|
+
*
|
|
239
|
+
* ### Custom CSS Properties
|
|
240
|
+
*
|
|
241
|
+
* The following custom CSS properties are available for styling:
|
|
242
|
+
*
|
|
243
|
+
* Custom CSS property | Description
|
|
244
|
+
* --------------------------------------|-------------
|
|
245
|
+
* `--vaadin-context-menu-offset-top` | Used as an offset when using `position` and the context menu is aligned vertically below the target
|
|
246
|
+
* `--vaadin-context-menu-offset-bottom` | Used as an offset when using `position` and the context menu is aligned vertically above the target
|
|
247
|
+
* `--vaadin-context-menu-offset-start` | Used as an offset when using `position` and the context menu is aligned horizontally after the target
|
|
248
|
+
* `--vaadin-context-menu-offset-end` | Used as an offset when using `position` and the context menu is aligned horizontally before the target
|
|
216
249
|
*
|
|
217
250
|
* See [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.
|
|
218
251
|
*
|
|
219
252
|
* ### Internal components
|
|
220
253
|
*
|
|
221
|
-
* When using `items` API
|
|
222
|
-
* internal components are themable:
|
|
254
|
+
* When using `items` API the following internal components are themable:
|
|
223
255
|
*
|
|
224
256
|
* - `<vaadin-context-menu-item>` - has the same API as [`<vaadin-item>`](#/elements/vaadin-item).
|
|
225
257
|
* - `<vaadin-context-menu-list-box>` - has the same API as [`<vaadin-list-box>`](#/elements/vaadin-list-box).
|
|
@@ -231,13 +263,19 @@ export interface ContextMenuEventMap<TItem extends ContextMenuItem = ContextMenu
|
|
|
231
263
|
* ---------- |-------------
|
|
232
264
|
* `expanded` | Expanded parent item.
|
|
233
265
|
*
|
|
234
|
-
* Note: the `theme` attribute value set on `<vaadin-context-menu>` is
|
|
235
|
-
* propagated to the internal components listed above.
|
|
236
|
-
*
|
|
237
266
|
* @fires {CustomEvent} opened-changed - Fired when the `opened` property changes.
|
|
238
267
|
* @fires {CustomEvent} item-selected - Fired when an item is selected when the context menu is populated using the `items` API.
|
|
268
|
+
* @fires {CustomEvent} closed - Fired when the context menu is closed.
|
|
239
269
|
*/
|
|
240
270
|
declare class ContextMenu<TItem extends ContextMenuItem = ContextMenuItem> extends HTMLElement {
|
|
271
|
+
/**
|
|
272
|
+
* Position of the overlay with respect to the target.
|
|
273
|
+
* Supported values: null, `top-start`, `top`, `top-end`,
|
|
274
|
+
* `bottom-start`, `bottom`, `bottom-end`, `start-top`,
|
|
275
|
+
* `start`, `start-bottom`, `end-top`, `end`, `end-bottom`.
|
|
276
|
+
*/
|
|
277
|
+
position: ContextMenuPosition | null | undefined;
|
|
278
|
+
|
|
241
279
|
addEventListener<K extends keyof ContextMenuEventMap>(
|
|
242
280
|
type: K,
|
|
243
281
|
listener: (this: ContextMenu<TItem>, ev: ContextMenuEventMap<TItem>[K]) => void,
|
|
@@ -253,7 +291,6 @@ declare class ContextMenu<TItem extends ContextMenuItem = ContextMenuItem> exten
|
|
|
253
291
|
|
|
254
292
|
interface ContextMenu<TItem extends ContextMenuItem = ContextMenuItem>
|
|
255
293
|
extends ContextMenuMixinClass<TItem>,
|
|
256
|
-
OverlayClassMixinClass,
|
|
257
294
|
ElementMixinClass,
|
|
258
295
|
ThemePropertyMixinClass {}
|
|
259
296
|
|