Skip to content

Commit 5458f76

Browse files
authored
refactor!: update popover overlay to use native popover (#9785)
1 parent 368f6b0 commit 5458f76

19 files changed

+300
-264
lines changed

dev/dialog.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import '@vaadin/dialog';
1616
import '@vaadin/icon';
1717
import '@vaadin/icons';
18+
import '@vaadin/popover';
1819
</script>
1920

2021
<style>
@@ -51,6 +52,17 @@
5152
if (root.firstChild) {
5253
return;
5354
}
55+
56+
root.innerHTML = `
57+
<button>I have a popover</button>
58+
<vaadin-popover>
59+
<div>Popover content</div>
60+
</vaadin-popover>
61+
`;
62+
63+
const popover = root.querySelector('vaadin-popover');
64+
popover.target = root.querySelector('button');
65+
5466
root.append(scope.cloneNode(true));
5567
root.querySelector('vaadin-checkbox-group').value = defaultOptions;
5668
root.querySelector('vaadin-button').addEventListener('click', openDialog);

dev/popover.html

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,32 +9,23 @@
99
<script type="module" src="./common.js"></script>
1010

1111
<script type="module">
12-
import '@vaadin/button';
13-
import '@vaadin/horizontal-layout';
12+
import '@vaadin/checkbox-group';
1413
import '@vaadin/popover';
1514
import '@vaadin/radio-group';
16-
import '@vaadin/text-field';
1715
</script>
1816
</head>
1917

2018
<body>
2119
<style>
2220
#wrapper {
2321
width: 100%;
22+
min-width: 350px;
2423
height: 350px;
2524
display: flex;
2625
justify-content: center;
2726
align-items: center;
2827
margin: 1rem;
29-
}
30-
31-
#target {
32-
width: 150px;
33-
height: 150px;
34-
display: flex;
35-
justify-content: center;
36-
align-items: center;
37-
border: solid 1px #e2e2e2;
28+
gap: 1rem;
3829
}
3930
</style>
4031

@@ -53,9 +44,19 @@
5344
<vaadin-radio-button value="end-bottom" label="End Bottom"></vaadin-radio-button>
5445
</vaadin-radio-group>
5546

47+
<vaadin-checkbox-group id="triggerGroup" label="Trigger" theme="horizontal">
48+
<vaadin-checkbox value="click" label="Click"></vaadin-checkbox>
49+
<vaadin-checkbox value="focus" label="Focus"></vaadin-checkbox>
50+
<vaadin-checkbox value="hover" label="Hover"></vaadin-checkbox>
51+
</vaadin-checkbox-group>
52+
5653
<div id="wrapper">
57-
<div id="target">Save</div>
58-
<vaadin-popover for="target" theme="arrow"></vaadin-popover>
54+
<input placeholder="Before" />
55+
56+
<input id="target" placeholder="Target" />
57+
<vaadin-popover for="target" theme="arrow" id="popover"></vaadin-popover>
58+
59+
<input placeholder="After" />
5960
</div>
6061

6162
<script type="module">
@@ -66,24 +67,30 @@
6667
popover.position = e.target.value;
6768
});
6869

70+
const checkboxGroup = document.querySelector('#triggerGroup');
71+
checkboxGroup.value = ['click'];
72+
73+
checkboxGroup.addEventListener('change', (e) => {
74+
popover.trigger = checkboxGroup.value;
75+
});
76+
6977
popover.renderer = (root) => {
7078
if (root.firstChild) {
7179
return;
7280
}
7381

74-
const layout = document.createElement('vaadin-horizontal-layout');
75-
layout.setAttribute('theme', 'spacing');
76-
layout.style.alignItems = 'end';
77-
78-
const field = document.createElement('vaadin-text-field');
79-
field.label = 'Discount code';
82+
const input = document.createElement('input');
8083

81-
const button = document.createElement('vaadin-button');
82-
button.textContent = 'Apply';
84+
const nested = document.createElement('vaadin-popover');
85+
nested.setAttribute('theme', 'arrow');
86+
nested.trigger = ['click'];
87+
nested.target = input;
8388

84-
layout.append(field, button);
89+
nested.renderer = (root2) => {
90+
root2.innerHTML = '<input placeholder="Popover 2" />';
91+
};
8592

86-
root.append(layout);
93+
root.append(input, nested);
8794
};
8895
</script>
8996
</body>

packages/popover/src/styles/vaadin-popover-overlay-core-styles.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@ import { css } from 'lit';
77
import { overlayStyles } from '@vaadin/overlay/src/styles/vaadin-overlay-core-styles.js';
88

99
const popoverOverlay = css`
10+
:host {
11+
--_default-offset: 0;
12+
}
13+
1014
:host([modeless][with-backdrop]) [part='backdrop'] {
1115
pointer-events: none;
1216
}
1317
1418
:host([position^='top'][top-aligned]) [part='overlay'],
1519
:host([position^='bottom'][top-aligned]) [part='overlay'] {
16-
margin-top: var(--vaadin-popover-offset-top, 0);
20+
margin-top: var(--vaadin-popover-offset-top, var(--_default-offset));
1721
}
1822
1923
[part='overlay'] {
@@ -32,25 +36,27 @@ const popoverOverlay = css`
3236
[part='overlay']::before {
3337
position: absolute;
3438
content: '';
35-
inset-block: calc(var(--vaadin-popover-offset-top, 0) * -1) calc(var(--vaadin-popover-offset-bottom, 0) * -1);
36-
inset-inline: calc(var(--vaadin-popover-offset-start, 0) * -1) calc(var(--vaadin-popover-offset-end, 0) * -1);
39+
inset-block: calc(var(--vaadin-popover-offset-top, var(--_default-offset)) * -1)
40+
calc(var(--vaadin-popover-offset-bottom, var(--_default-offset)) * -1);
41+
inset-inline: calc(var(--vaadin-popover-offset-start, var(--_default-offset)) * -1)
42+
calc(var(--vaadin-popover-offset-end, var(--_default-offset)) * -1);
3743
z-index: -1;
3844
pointer-events: auto;
3945
}
4046
4147
:host([position^='top'][bottom-aligned]) [part='overlay'],
4248
:host([position^='bottom'][bottom-aligned]) [part='overlay'] {
43-
margin-bottom: var(--vaadin-popover-offset-bottom, 0);
49+
margin-bottom: var(--vaadin-popover-offset-bottom, var(--_default-offset));
4450
}
4551
4652
:host([position^='start'][start-aligned]) [part='overlay'],
4753
:host([position^='end'][start-aligned]) [part='overlay'] {
48-
margin-inline-start: var(--vaadin-popover-offset-start, 0);
54+
margin-inline-start: var(--vaadin-popover-offset-start, var(--_default-offset));
4955
}
5056
5157
:host([position^='start'][end-aligned]) [part='overlay'],
5258
:host([position^='end'][end-aligned]) [part='overlay'] {
53-
margin-inline-end: var(--vaadin-popover-offset-end, 0);
59+
margin-inline-end: var(--vaadin-popover-offset-end, var(--_default-offset));
5460
}
5561
5662
[part='arrow'] {

packages/popover/src/vaadin-popover-overlay-mixin.js

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,6 @@
55
*/
66
import { OverlayMixin } from '@vaadin/overlay/src/vaadin-overlay-mixin.js';
77
import { PositionMixin } from '@vaadin/overlay/src/vaadin-overlay-position-mixin.js';
8-
import { setNestedOverlay } from '@vaadin/overlay/src/vaadin-overlay-stack-mixin.js';
9-
10-
/**
11-
* Returns the closest parent overlay for given node, if any.
12-
* @param {HTMLElement} node
13-
* @return {HTMLElement}
14-
*/
15-
const getClosestOverlay = (node) => {
16-
let n = node;
17-
18-
while (n && n !== node.ownerDocument) {
19-
n = n.parentNode || n.host;
20-
21-
if (n && n._hasOverlayStackMixin) {
22-
return n;
23-
}
24-
}
25-
26-
return null;
27-
};
288

299
/**
3010
* A mixin providing common popover overlay functionality.
@@ -44,19 +24,6 @@ export const PopoverOverlayMixin = (superClass) =>
4424
};
4525
}
4626

47-
static get observers() {
48-
return ['__openedOrTargetChanged(opened, positionTarget)'];
49-
}
50-
51-
/**
52-
* Tag name prefix used by custom properties.
53-
* @protected
54-
* @return {string}
55-
*/
56-
get _tagNamePrefix() {
57-
return 'vaadin-popover';
58-
}
59-
6027
/**
6128
* @protected
6229
* @override
@@ -68,15 +35,6 @@ export const PopoverOverlayMixin = (superClass) =>
6835
return;
6936
}
7037

71-
// Copy custom properties from the owner
72-
if (this.owner) {
73-
const style = getComputedStyle(this.owner);
74-
['top', 'bottom', 'start', 'end'].forEach((prop) => {
75-
const propertyName = `--${this._tagNamePrefix}-offset-${prop}`;
76-
this.style.setProperty(propertyName, style.getPropertyValue(propertyName));
77-
});
78-
}
79-
8038
this.removeAttribute('arrow-centered');
8139

8240
// Center the overlay horizontally
@@ -114,14 +72,4 @@ export const PopoverOverlayMixin = (superClass) =>
11472
this.style.top = `${overlayRect.top + offset}px`;
11573
}
11674
}
117-
118-
/** @private */
119-
__openedOrTargetChanged(opened, target) {
120-
if (target) {
121-
const parent = getClosestOverlay(target);
122-
if (parent) {
123-
setNestedOverlay(parent, opened ? this : null);
124-
}
125-
}
126-
}
12775
};

packages/popover/src/vaadin-popover-overlay.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,38 @@ class PopoverOverlay extends PopoverOverlayMixin(
4343
</div>
4444
`;
4545
}
46+
47+
/**
48+
* @override
49+
* @protected
50+
*/
51+
get _contentRoot() {
52+
return this.owner;
53+
}
54+
55+
/**
56+
* @override
57+
* @protected
58+
*/
59+
get _modalRoot() {
60+
return this.owner;
61+
}
62+
63+
/**
64+
* @protected
65+
* @override
66+
*/
67+
_attachOverlay() {
68+
this.showPopover();
69+
}
70+
71+
/**
72+
* @protected
73+
* @override
74+
*/
75+
_detachOverlay() {
76+
this.hidePopover();
77+
}
4678
}
4779

4880
defineCustomElement(PopoverOverlay);

packages/popover/src/vaadin-popover.d.ts

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,13 @@ export type PopoverEventMap = HTMLElementEventMap & PopoverCustomEventMap;
3737
*
3838
* ### Styling
3939
*
40-
* `<vaadin-popover>` uses `<vaadin-popover-overlay>` internal
41-
* themable component as the actual visible overlay.
42-
*
43-
* See [`<vaadin-overlay>`](#/elements/vaadin-overlay) documentation
44-
* for `<vaadin-popover-overlay>` parts.
45-
*
46-
* In addition to `<vaadin-overlay>` parts, the following parts are available for styling:
40+
* The following shadow DOM parts are available for styling:
4741
*
4842
* Part name | Description
4943
* -----------------|-------------------------------------------
44+
* `backdrop` | Backdrop of the overlay
45+
* `overlay` | The overlay container
46+
* `content` | The overlay content
5047
* `arrow` | Optional arrow pointing to the target when using `theme="arrow"`
5148
*
5249
* The following state attributes are available for styling:
@@ -55,9 +52,6 @@ export type PopoverEventMap = HTMLElementEventMap & PopoverCustomEventMap;
5552
* -----------------|----------------------------------------
5653
* `position` | Reflects the `position` property value.
5754
*
58-
* Note: the `theme` attribute value set on `<vaadin-popover>` is
59-
* propagated to the internal `<vaadin-popover-overlay>` component.
60-
*
6155
* ### Custom CSS Properties
6256
*
6357
* The following custom CSS properties are available on the `<vaadin-popover>` element:
@@ -96,14 +90,14 @@ declare class Popover extends PopoverPositionMixin(
9690
static setDefaultHoverDelay(hoverDelay: number): void;
9791

9892
/**
99-
* String used to label the overlay to screen reader users.
93+
* String used to label the popover to screen reader users.
10094
*
10195
* @attr {string} accessible-name
10296
*/
10397
accessibleName: string | null | undefined;
10498

10599
/**
106-
* Id of the element used as label of the overlay to screen reader users.
100+
* Id of the element used as label of the popover to screen reader users.
107101
*
108102
* @attr {string} accessible-name-ref
109103
*/

0 commit comments

Comments
 (0)