@vaadin/context-menu 22.0.0-beta1 → 22.0.1
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/README.md +25 -28
- package/package.json +12 -11
- package/src/vaadin-context-menu-overlay.js +31 -7
- package/src/vaadin-context-menu.js +37 -77
- package/src/vaadin-contextmenu-event.js +4 -6
- package/src/vaadin-contextmenu-items-mixin.d.ts +4 -9
- package/src/vaadin-contextmenu-items-mixin.js +6 -22
- package/src/vaadin-device-detector.js +3 -11
- package/theme/lumo/vaadin-context-menu-styles.js +5 -4
- package/theme/material/vaadin-context-menu-styles.js +3 -3
package/README.md
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @vaadin/context-menu
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
|
5
|
-
[API documentation ↗](https://vaadin.com/components/vaadin-context-menu/html-api)
|
|
3
|
+
A web component that can be attached to any component to display a context menu.
|
|
6
4
|
|
|
7
|
-
[
|
|
5
|
+
[Documentation + Live Demo ↗](https://vaadin.com/docs/latest/ds/components/context-menu)
|
|
8
6
|
|
|
9
7
|
[](https://www.npmjs.com/package/@vaadin/context-menu)
|
|
10
|
-
[](https://vaadin.com/directory/component/vaadinvaadin-context-menu)
|
|
11
8
|
[](https://discord.gg/PHmkCKC)
|
|
12
9
|
|
|
13
10
|
```html
|
|
@@ -36,50 +33,50 @@
|
|
|
36
33
|
</script>
|
|
37
34
|
```
|
|
38
35
|
|
|
39
|
-
[<img src="https://raw.githubusercontent.com/vaadin/
|
|
36
|
+
[<img src="https://raw.githubusercontent.com/vaadin/web-components/master/packages/context-menu/screenshot.png" width="493" alt="Screenshot of vaadin-context-menu">](https://vaadin.com/docs/latest/ds/components/context-menu)
|
|
40
37
|
|
|
41
38
|
**Note:** [`<vaadin-list-box>`](https://github.com/vaadin/vaadin-list-box) component used in the above example should be installed and imported separately.
|
|
42
39
|
|
|
43
40
|
## Installation
|
|
44
41
|
|
|
45
|
-
Install
|
|
42
|
+
Install the component:
|
|
46
43
|
|
|
47
44
|
```sh
|
|
48
|
-
npm i @vaadin/context-menu
|
|
45
|
+
npm i @vaadin/context-menu
|
|
49
46
|
```
|
|
50
47
|
|
|
51
|
-
Once installed, import
|
|
48
|
+
Once installed, import the component in your application:
|
|
52
49
|
|
|
53
50
|
```js
|
|
54
|
-
import '@vaadin/context-menu
|
|
51
|
+
import '@vaadin/context-menu';
|
|
55
52
|
```
|
|
56
53
|
|
|
57
|
-
##
|
|
54
|
+
## Themes
|
|
58
55
|
|
|
59
|
-
Vaadin components
|
|
56
|
+
Vaadin components come with two built-in [themes](https://vaadin.com/docs/latest/ds/customization/using-themes), Lumo and Material.
|
|
57
|
+
The [main entrypoint](https://github.com/vaadin/web-components/blob/master/packages/context-menu/vaadin-context-menu.js) of the package uses the Lumo theme.
|
|
60
58
|
|
|
61
|
-
To use the Material theme, import the
|
|
59
|
+
To use the Material theme, import the component from the `theme/material` folder:
|
|
62
60
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
`theme/lumo/vaadin-context-menu.js`
|
|
68
|
-
|
|
69
|
-
- The component with the Material theme:
|
|
70
|
-
|
|
71
|
-
`theme/material/vaadin-context-menu.js`
|
|
61
|
+
```js
|
|
62
|
+
import '@vaadin/context-menu/theme/material/vaadin-context-menu.js';
|
|
63
|
+
```
|
|
72
64
|
|
|
73
|
-
|
|
65
|
+
You can also import the Lumo version of the component explicitly:
|
|
74
66
|
|
|
75
|
-
|
|
67
|
+
```js
|
|
68
|
+
import '@vaadin/context-menu/theme/lumo/vaadin-context-menu.js';
|
|
69
|
+
```
|
|
76
70
|
|
|
77
|
-
|
|
71
|
+
Finally, you can import the un-themed component from the `src` folder to get a minimal starting point:
|
|
78
72
|
|
|
79
|
-
|
|
73
|
+
```js
|
|
74
|
+
import '@vaadin/context-menu/src/vaadin-context-menu.js';
|
|
75
|
+
```
|
|
80
76
|
|
|
81
77
|
## License
|
|
82
78
|
|
|
83
79
|
Apache License 2.0
|
|
84
80
|
|
|
85
|
-
Vaadin collects development time
|
|
81
|
+
Vaadin collects usage statistics at development time to improve this product.
|
|
82
|
+
For details and to opt-out, see https://github.com/vaadin/vaadin-usage-statistics.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/context-menu",
|
|
3
|
-
"version": "22.0.
|
|
3
|
+
"version": "22.0.1",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -32,21 +32,22 @@
|
|
|
32
32
|
"polymer"
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
|
+
"@open-wc/dedupe-mixin": "^1.3.0",
|
|
35
36
|
"@polymer/iron-media-query": "^3.0.0",
|
|
36
37
|
"@polymer/polymer": "^3.0.0",
|
|
37
|
-
"@vaadin/component-base": "22.0.
|
|
38
|
-
"@vaadin/item": "22.0.
|
|
39
|
-
"@vaadin/list-box": "22.0.
|
|
40
|
-
"@vaadin/vaadin-lumo-styles": "22.0.
|
|
41
|
-
"@vaadin/vaadin-material-styles": "22.0.
|
|
42
|
-
"@vaadin/vaadin-overlay": "22.0.
|
|
43
|
-
"@vaadin/vaadin-themable-mixin": "22.0.
|
|
38
|
+
"@vaadin/component-base": "^22.0.1",
|
|
39
|
+
"@vaadin/item": "^22.0.1",
|
|
40
|
+
"@vaadin/list-box": "^22.0.1",
|
|
41
|
+
"@vaadin/vaadin-lumo-styles": "^22.0.1",
|
|
42
|
+
"@vaadin/vaadin-material-styles": "^22.0.1",
|
|
43
|
+
"@vaadin/vaadin-overlay": "^22.0.1",
|
|
44
|
+
"@vaadin/vaadin-themable-mixin": "^22.0.1"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
46
47
|
"@esm-bundle/chai": "^4.3.4",
|
|
47
|
-
"@vaadin/polymer-legacy-adapter": "22.0.
|
|
48
|
-
"@vaadin/testing-helpers": "^0.3.
|
|
48
|
+
"@vaadin/polymer-legacy-adapter": "^22.0.1",
|
|
49
|
+
"@vaadin/testing-helpers": "^0.3.2",
|
|
49
50
|
"sinon": "^9.2.1"
|
|
50
51
|
},
|
|
51
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "2b0a2bff0369d6020f7cc33ad35506aa2d1f6f68"
|
|
52
53
|
}
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* Copyright (c) 2021 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
-
import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js';
|
|
7
6
|
import { OverlayElement } from '@vaadin/vaadin-overlay/src/vaadin-overlay.js';
|
|
7
|
+
import { PositionMixin } from '@vaadin/vaadin-overlay/src/vaadin-overlay-position-mixin.js';
|
|
8
|
+
import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
8
9
|
|
|
9
10
|
registerStyles(
|
|
10
11
|
'vaadin-context-menu-overlay',
|
|
@@ -36,7 +37,7 @@ registerStyles(
|
|
|
36
37
|
* @extends OverlayElement
|
|
37
38
|
* @protected
|
|
38
39
|
*/
|
|
39
|
-
class ContextMenuOverlay extends OverlayElement {
|
|
40
|
+
class ContextMenuOverlay extends PositionMixin(OverlayElement) {
|
|
40
41
|
static get is() {
|
|
41
42
|
return 'vaadin-context-menu-overlay';
|
|
42
43
|
}
|
|
@@ -101,13 +102,36 @@ class ContextMenuOverlay extends OverlayElement {
|
|
|
101
102
|
return {
|
|
102
103
|
xMax: overlayRect.right - contentRect.width,
|
|
103
104
|
xMin: overlayRect.left + contentRect.width,
|
|
104
|
-
yMax
|
|
105
|
-
left: overlayRect.left,
|
|
106
|
-
right: overlayRect.right,
|
|
107
|
-
top: overlayRect.top,
|
|
108
|
-
width: contentRect.width
|
|
105
|
+
yMax
|
|
109
106
|
};
|
|
110
107
|
}
|
|
108
|
+
|
|
109
|
+
_updatePosition() {
|
|
110
|
+
super._updatePosition();
|
|
111
|
+
|
|
112
|
+
if (this.positionTarget && this.parentOverlay) {
|
|
113
|
+
// This overlay is positioned by a parent menu item,
|
|
114
|
+
// adjust the position by the overlay content paddings
|
|
115
|
+
const content = this.$.content;
|
|
116
|
+
const style = getComputedStyle(content);
|
|
117
|
+
|
|
118
|
+
// Horizontal adjustment
|
|
119
|
+
const isLeftAligned = !!this.style.left;
|
|
120
|
+
if (isLeftAligned) {
|
|
121
|
+
this.style.left = parseFloat(this.style.left) + parseFloat(style.paddingLeft) + 'px';
|
|
122
|
+
} else {
|
|
123
|
+
this.style.right = parseFloat(this.style.right) + parseFloat(style.paddingRight) + 'px';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Vertical adjustment
|
|
127
|
+
const isBottomAligned = !!this.style.bottom;
|
|
128
|
+
if (isBottomAligned) {
|
|
129
|
+
this.style.bottom = parseFloat(this.style.bottom) - parseFloat(style.paddingBottom) + 'px';
|
|
130
|
+
} else {
|
|
131
|
+
this.style.top = parseFloat(this.style.top) - parseFloat(style.paddingTop) + 'px';
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
111
135
|
}
|
|
112
136
|
|
|
113
137
|
customElements.define(ContextMenuOverlay.is, ContextMenuOverlay);
|
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
* Copyright (c) 2021 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
-
import
|
|
7
|
-
import
|
|
6
|
+
import './vaadin-contextmenu-event.js';
|
|
7
|
+
import './vaadin-device-detector.js';
|
|
8
|
+
import './vaadin-context-menu-overlay.js';
|
|
8
9
|
import { GestureEventListeners } from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
|
|
10
|
+
import { addListener, gestures, removeListener } from '@polymer/polymer/lib/utils/gestures.js';
|
|
11
|
+
import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
|
|
9
12
|
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
|
|
10
13
|
import { processTemplates } from '@vaadin/component-base/src/templates.js';
|
|
11
14
|
import { ThemePropertyMixin } from '@vaadin/vaadin-themable-mixin/vaadin-theme-property-mixin.js';
|
|
12
15
|
import { ItemsMixin } from './vaadin-contextmenu-items-mixin.js';
|
|
13
|
-
import './vaadin-contextmenu-event.js';
|
|
14
|
-
import './vaadin-device-detector.js';
|
|
15
|
-
import './vaadin-context-menu-overlay.js';
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* `<vaadin-context-menu>` is a Web Component for creating context menus.
|
|
@@ -552,6 +552,16 @@ class ContextMenu extends ElementMixin(ThemePropertyMixin(ItemsMixin(GestureEven
|
|
|
552
552
|
/** @private */
|
|
553
553
|
__alignOverlayPosition() {
|
|
554
554
|
const overlay = this.$.overlay;
|
|
555
|
+
|
|
556
|
+
if (overlay.positionTarget) {
|
|
557
|
+
// The overlay is positioned relative to another node, for example, a
|
|
558
|
+
// menu item in a nested submenu structure where this overlay lists
|
|
559
|
+
// the items for another submenu.
|
|
560
|
+
// It means that the overlay positioning is controlled by
|
|
561
|
+
// vaadin-overlay-position-mixin so no manual alignment is needed.
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
|
|
555
565
|
const style = overlay.style;
|
|
556
566
|
|
|
557
567
|
// Reset all properties before measuring
|
|
@@ -559,89 +569,39 @@ class ContextMenu extends ElementMixin(ThemePropertyMixin(ItemsMixin(GestureEven
|
|
|
559
569
|
['right-aligned', 'end-aligned', 'bottom-aligned'].forEach((attr) => overlay.removeAttribute(attr));
|
|
560
570
|
|
|
561
571
|
// Maximum x and y values are imposed by content size and overlay limits.
|
|
562
|
-
const { xMax, xMin, yMax
|
|
572
|
+
const { xMax, xMin, yMax } = overlay.getBoundaries();
|
|
563
573
|
// Reuse saved x and y event values, in order to this method be used async
|
|
564
|
-
// in the `vaadin-overlay-change` which guarantees that overlay is ready
|
|
565
|
-
|
|
566
|
-
|
|
574
|
+
// in the `vaadin-overlay-change` which guarantees that overlay is ready.
|
|
575
|
+
// The valus represent an anchor position on the page where the contextmenu
|
|
576
|
+
// event took place.
|
|
577
|
+
let x = this.__x;
|
|
578
|
+
const y = this.__y;
|
|
567
579
|
|
|
568
580
|
// Select one overlay corner and move to the event x/y position.
|
|
569
581
|
// Then set styling attrs for flex-aligning the content appropriately.
|
|
570
582
|
const wdthVport = document.documentElement.clientWidth;
|
|
571
583
|
const hghtVport = document.documentElement.clientHeight;
|
|
572
584
|
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
const getPadding = (el, direction) => {
|
|
582
|
-
return parseFloat(getComputedStyle(el.$.content)['padding' + direction]);
|
|
583
|
-
};
|
|
584
|
-
const dimensionToSet = parseFloat(parentStyle[this.__isRTL ? 'left' : 'right']) + parentContentRect.width;
|
|
585
|
-
const padding = getPadding(parent, 'Left') + getPadding(overlay, 'Right');
|
|
586
|
-
|
|
587
|
-
// Preserve end-aligned, if possible.
|
|
588
|
-
if (wdthVport - (dimensionToSet - padding) > width) {
|
|
589
|
-
this._setEndAligned(overlay);
|
|
590
|
-
style[this.__isRTL ? 'left' : 'right'] = dimensionToSet + 'px';
|
|
591
|
-
alignedToParent = true;
|
|
592
|
-
}
|
|
593
|
-
} else if (x < parentContentRect.x) {
|
|
594
|
-
// Check if sub menu opens on the left side and the parent menu is not right aligned.
|
|
595
|
-
// If so, use actual width of the submenu content instead of the parent menu content.
|
|
596
|
-
x = x - (width - parentContentRect.width);
|
|
585
|
+
if (!this.__isRTL) {
|
|
586
|
+
if (x < wdthVport / 2 || x < xMax) {
|
|
587
|
+
// Menu is displayed in the right side of the anchor
|
|
588
|
+
style.left = x + 'px';
|
|
589
|
+
} else {
|
|
590
|
+
// Menu is displayed in the left side of the anchor
|
|
591
|
+
style.right = Math.max(0, wdthVport - x) + 'px';
|
|
592
|
+
this._setEndAligned(overlay);
|
|
597
593
|
}
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
// Sub-menu is displayed in the right side of root menu
|
|
603
|
-
if ((x < wdthVport / 2 || x < xMax) && !parent) {
|
|
604
|
-
style.left = x + 'px';
|
|
605
|
-
} else if (parent && wdthVport - parentContentRect.width - parentContentRect.left >= parentContentRect.width) {
|
|
606
|
-
// Sub-menu is displayed in the right side of root menu If it is nested menu
|
|
607
|
-
style.left = parentContentRect.left + parentContentRect.width + 'px';
|
|
608
|
-
} else if (parent) {
|
|
609
|
-
// Sub-menu is displayed in the left side of root menu If it is nested menu
|
|
610
|
-
style.right = 'auto';
|
|
611
|
-
style.left =
|
|
612
|
-
Math.max(
|
|
613
|
-
overlay.getBoundingClientRect().left,
|
|
614
|
-
parentContentRect.left - overlay.getBoundingClientRect().width
|
|
615
|
-
) + 'px';
|
|
616
|
-
this._setEndAligned(overlay);
|
|
617
|
-
} else {
|
|
618
|
-
// Sub-menu is displayed in the left side of root menu
|
|
619
|
-
style.right = Math.max(0, wdthVport - x) + 'px';
|
|
620
|
-
this._setEndAligned(overlay);
|
|
621
|
-
}
|
|
594
|
+
} else {
|
|
595
|
+
// Menu is displayed in the left side of the anchor
|
|
596
|
+
if (x > wdthVport / 2 || x > xMin) {
|
|
597
|
+
style.right = Math.max(0, wdthVport - x) + 'px';
|
|
622
598
|
} else {
|
|
623
|
-
//
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
} else if (parent && parentContentRect.left >= parentContentRect.width) {
|
|
627
|
-
// Sub-menu is displayed in the left side of root menu If it is nested menu
|
|
628
|
-
style.right = wdthVport - parentContentRect.right + parentContentRect.width + 'px';
|
|
629
|
-
} else if (parent) {
|
|
630
|
-
// Sub-menu is displayed in the right side of root menu If it is nested menu
|
|
631
|
-
style.right = 'auto';
|
|
632
|
-
style.left =
|
|
633
|
-
Math.max(
|
|
634
|
-
overlay.getBoundingClientRect().left - overlay.getBoundingClientRect().width,
|
|
635
|
-
parentContentRect.right
|
|
636
|
-
) + 'px';
|
|
637
|
-
this._setEndAligned(overlay);
|
|
638
|
-
} else {
|
|
639
|
-
// Sub-menu is displayed in the left side of root menu
|
|
640
|
-
style.left = x + 'px';
|
|
641
|
-
this._setEndAligned(overlay);
|
|
642
|
-
}
|
|
599
|
+
// Menu is displayed in the left side of the anchor
|
|
600
|
+
style.left = x + 'px';
|
|
601
|
+
this._setEndAligned(overlay);
|
|
643
602
|
}
|
|
644
603
|
}
|
|
604
|
+
|
|
645
605
|
if (y < hghtVport / 2 || y < yMax) {
|
|
646
606
|
style.top = y + 'px';
|
|
647
607
|
} else {
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* Copyright (c) 2021 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { prevent, register } from '@polymer/polymer/lib/utils/gestures.js';
|
|
7
|
+
import { isIOS } from '@vaadin/component-base/src/browser-utils.js';
|
|
7
8
|
|
|
8
9
|
register({
|
|
9
10
|
name: 'vaadin-contextmenu',
|
|
@@ -16,10 +17,7 @@ register({
|
|
|
16
17
|
emits: ['vaadin-contextmenu'],
|
|
17
18
|
|
|
18
19
|
info: {
|
|
19
|
-
sourceEvent: null
|
|
20
|
-
_ios:
|
|
21
|
-
(/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) ||
|
|
22
|
-
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)
|
|
20
|
+
sourceEvent: null
|
|
23
21
|
},
|
|
24
22
|
|
|
25
23
|
reset: function () {
|
|
@@ -50,7 +48,7 @@ register({
|
|
|
50
48
|
this._timerId = setTimeout(() => {
|
|
51
49
|
const ct = e.changedTouches[0];
|
|
52
50
|
if (!e.shiftKey) {
|
|
53
|
-
if (
|
|
51
|
+
if (isIOS) {
|
|
54
52
|
this._fired = true;
|
|
55
53
|
this.fire(t, ct.clientX, ct.clientY);
|
|
56
54
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Copyright (c) 2021 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
+
import { Constructor } from '@open-wc/dedupe-mixin';
|
|
6
7
|
import { Item } from '@vaadin/item/src/vaadin-item.js';
|
|
7
8
|
import { ListBox } from '@vaadin/list-box/src/vaadin-list-box.js';
|
|
8
9
|
|
|
@@ -36,14 +37,10 @@ declare global {
|
|
|
36
37
|
*/
|
|
37
38
|
declare class ContextMenuListBox extends ListBox {}
|
|
38
39
|
|
|
39
|
-
declare function ItemsMixin<T extends
|
|
40
|
+
export declare function ItemsMixin<T extends Constructor<HTMLElement>>(base: T): T & Constructor<ItemsMixinClass>;
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
interface ItemsMixin {
|
|
46
|
-
readonly __isRTL: boolean;
|
|
42
|
+
export declare class ItemsMixinClass {
|
|
43
|
+
protected readonly __isRTL: boolean;
|
|
47
44
|
|
|
48
45
|
/**
|
|
49
46
|
* Defines a (hierarchical) menu structure for the component.
|
|
@@ -75,5 +72,3 @@ interface ItemsMixin {
|
|
|
75
72
|
*/
|
|
76
73
|
items: ContextMenuItem[] | undefined;
|
|
77
74
|
}
|
|
78
|
-
|
|
79
|
-
export { ItemsMixin, ItemsMixinConstructor };
|
|
@@ -156,17 +156,13 @@ export const ItemsMixin = (superClass) =>
|
|
|
156
156
|
subMenu.items = itemElement._item.children;
|
|
157
157
|
subMenu.listenOn = itemElement;
|
|
158
158
|
|
|
159
|
-
const itemRect = itemElement.getBoundingClientRect();
|
|
160
|
-
|
|
161
|
-
const content = subMenu.$.overlay.$.content;
|
|
162
|
-
const style = getComputedStyle(content);
|
|
163
159
|
const parent = this.$.overlay;
|
|
164
|
-
const y = parent.hasAttribute('bottom-aligned')
|
|
165
|
-
? itemRect.bottom + parseFloat(style.paddingBottom)
|
|
166
|
-
: itemRect.top - parseFloat(style.paddingTop);
|
|
167
160
|
|
|
168
|
-
|
|
169
|
-
|
|
161
|
+
const subMenuOverlay = subMenu.$.overlay;
|
|
162
|
+
subMenuOverlay.positionTarget = itemElement;
|
|
163
|
+
subMenuOverlay.noHorizontalOverlap = true;
|
|
164
|
+
// Store the reference parent overlay
|
|
165
|
+
subMenuOverlay._setParentOverlay(parent);
|
|
170
166
|
|
|
171
167
|
// Set theme attribute from parent element
|
|
172
168
|
if (parent.theme) {
|
|
@@ -175,24 +171,12 @@ export const ItemsMixin = (superClass) =>
|
|
|
175
171
|
subMenu.removeAttribute('theme');
|
|
176
172
|
}
|
|
177
173
|
|
|
178
|
-
|
|
174
|
+
const content = subMenu.$.overlay.$.content;
|
|
179
175
|
content.style.minWidth = '';
|
|
180
|
-
if (document.documentElement.clientWidth - itemRect.right > itemRect.width) {
|
|
181
|
-
// There's room on the right side
|
|
182
|
-
x = itemRect.right;
|
|
183
|
-
} else {
|
|
184
|
-
// Open on the left side
|
|
185
|
-
x = itemRect.left - itemRect.width;
|
|
186
|
-
// Make sure there's no gaps between the menus
|
|
187
|
-
content.style.minWidth = parent.$.content.clientWidth + 'px';
|
|
188
|
-
}
|
|
189
|
-
x = Math.max(x, 0);
|
|
190
176
|
|
|
191
177
|
itemElement.dispatchEvent(
|
|
192
178
|
new CustomEvent('opensubmenu', {
|
|
193
179
|
detail: {
|
|
194
|
-
x,
|
|
195
|
-
y,
|
|
196
180
|
children: itemElement._item.children
|
|
197
181
|
}
|
|
198
182
|
})
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* Copyright (c) 2021 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
-
import { PolymerElement, html } from '@polymer/polymer/polymer-element.js';
|
|
7
6
|
import '@polymer/iron-media-query/iron-media-query.js';
|
|
7
|
+
import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
|
|
8
|
+
import { isTouch } from '@vaadin/component-base/src/browser-utils.js';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Element for internal use only.
|
|
@@ -38,7 +39,7 @@ class DeviceDetector extends PolymerElement {
|
|
|
38
39
|
touch: {
|
|
39
40
|
type: Boolean,
|
|
40
41
|
notify: true,
|
|
41
|
-
value:
|
|
42
|
+
value: isTouch
|
|
42
43
|
},
|
|
43
44
|
|
|
44
45
|
/**
|
|
@@ -51,15 +52,6 @@ class DeviceDetector extends PolymerElement {
|
|
|
51
52
|
};
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
static _touch() {
|
|
55
|
-
try {
|
|
56
|
-
document.createEvent('TouchEvent');
|
|
57
|
-
return true;
|
|
58
|
-
} catch (err) {
|
|
59
|
-
return false;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
55
|
_phone(wide, touch) {
|
|
64
56
|
return !wide && touch;
|
|
65
57
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js';
|
|
2
1
|
import '@vaadin/vaadin-lumo-styles/spacing.js';
|
|
3
2
|
import '@vaadin/vaadin-lumo-styles/style.js';
|
|
4
|
-
import { menuOverlay } from '@vaadin/vaadin-lumo-styles/mixins/menu-overlay.js';
|
|
5
3
|
import '@vaadin/vaadin-lumo-styles/font-icons.js';
|
|
6
4
|
import '@vaadin/vaadin-lumo-styles/color.js';
|
|
7
5
|
import '@vaadin/vaadin-lumo-styles/sizing.js';
|
|
8
6
|
import '@vaadin/vaadin-lumo-styles/typography.js';
|
|
7
|
+
import { menuOverlay } from '@vaadin/vaadin-lumo-styles/mixins/menu-overlay.js';
|
|
8
|
+
import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
9
9
|
|
|
10
10
|
const contextMenuOverlay = css`
|
|
11
11
|
:host([phone]) {
|
|
@@ -90,13 +90,14 @@ registerStyles(
|
|
|
90
90
|
registerStyles(
|
|
91
91
|
'vaadin-context-menu-item',
|
|
92
92
|
css`
|
|
93
|
-
:
|
|
93
|
+
/* :hover needed to workaround https://github.com/vaadin/web-components/issues/3133 */
|
|
94
|
+
:host(:hover) {
|
|
94
95
|
user-select: none;
|
|
95
96
|
-ms-user-select: none;
|
|
96
97
|
-webkit-user-select: none;
|
|
97
98
|
}
|
|
98
99
|
|
|
99
|
-
:host(.vaadin-menu-item[menu-item-checked])::before {
|
|
100
|
+
:host(.vaadin-menu-item[menu-item-checked]) [part='checkmark']::before {
|
|
100
101
|
opacity: 1;
|
|
101
102
|
}
|
|
102
103
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js';
|
|
2
1
|
import '@vaadin/vaadin-material-styles/font-icons.js';
|
|
3
2
|
import '@vaadin/vaadin-material-styles/color.js';
|
|
4
|
-
import { menuOverlay } from '@vaadin/vaadin-material-styles/mixins/menu-overlay.js';
|
|
5
3
|
import '@vaadin/vaadin-material-styles/typography.js';
|
|
4
|
+
import { menuOverlay } from '@vaadin/vaadin-material-styles/mixins/menu-overlay.js';
|
|
5
|
+
import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
|
|
6
6
|
|
|
7
7
|
const contextMenuOverlay = css`
|
|
8
8
|
[part='overlay'] {
|
|
@@ -71,7 +71,7 @@ registerStyles(
|
|
|
71
71
|
display: block;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
:host(.vaadin-menu-item[menu-item-checked])::before {
|
|
74
|
+
:host(.vaadin-menu-item[menu-item-checked]) [part='checkmark']::before {
|
|
75
75
|
content: var(--material-icons-check);
|
|
76
76
|
}
|
|
77
77
|
|