@vaadin/popover 25.0.0-alpha2 → 25.0.0-alpha20

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/popover",
3
- "version": "25.0.0-alpha2",
3
+ "version": "25.0.0-alpha20",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -23,7 +23,6 @@
23
23
  "lit.d.ts",
24
24
  "lit.js",
25
25
  "src",
26
- "theme",
27
26
  "vaadin-*.d.ts",
28
27
  "vaadin-*.js",
29
28
  "web-types.json",
@@ -37,23 +36,23 @@
37
36
  ],
38
37
  "dependencies": {
39
38
  "@open-wc/dedupe-mixin": "^1.3.0",
40
- "@vaadin/a11y-base": "25.0.0-alpha2",
41
- "@vaadin/component-base": "25.0.0-alpha2",
42
- "@vaadin/lit-renderer": "25.0.0-alpha2",
43
- "@vaadin/overlay": "25.0.0-alpha2",
44
- "@vaadin/vaadin-lumo-styles": "25.0.0-alpha2",
45
- "@vaadin/vaadin-themable-mixin": "25.0.0-alpha2",
39
+ "@vaadin/a11y-base": "25.0.0-alpha20",
40
+ "@vaadin/component-base": "25.0.0-alpha20",
41
+ "@vaadin/lit-renderer": "25.0.0-alpha20",
42
+ "@vaadin/overlay": "25.0.0-alpha20",
43
+ "@vaadin/vaadin-themable-mixin": "25.0.0-alpha20",
46
44
  "lit": "^3.0.0"
47
45
  },
48
46
  "devDependencies": {
49
- "@vaadin/chai-plugins": "25.0.0-alpha2",
50
- "@vaadin/test-runner-commands": "25.0.0-alpha2",
47
+ "@vaadin/chai-plugins": "25.0.0-alpha20",
48
+ "@vaadin/test-runner-commands": "25.0.0-alpha20",
51
49
  "@vaadin/testing-helpers": "^2.0.0",
52
- "sinon": "^18.0.0"
50
+ "@vaadin/vaadin-lumo-styles": "25.0.0-alpha20",
51
+ "sinon": "^21.0.0"
53
52
  },
54
53
  "web-types": [
55
54
  "web-types.json",
56
55
  "web-types.lit.json"
57
56
  ],
58
- "gitHead": "67ffcd5355cf21ce1b5039c598525109fc4c164b"
57
+ "gitHead": "c948aae591a30b432f3784000d4677674cae56e0"
59
58
  }
@@ -27,7 +27,7 @@ export class PopoverRendererDirective extends LitRendererDirective<Popover, Popo
27
27
  }
28
28
 
29
29
  /**
30
- * A Lit directive for populating the content of the `<vaadin-popover-overlay>` element.
30
+ * A Lit directive for populating the content of the `<vaadin-popover>` element.
31
31
  *
32
32
  * The directive accepts a renderer callback returning a Lit template and assigns it to the popover
33
33
  * via the `renderer` property. The renderer is called once to populate the content when assigned
@@ -51,6 +51,7 @@ export class PopoverRendererDirective extends LitRendererDirective<Popover, Popo
51
51
  * @param renderer the renderer callback that returns a Lit template.
52
52
  * @param dependencies a single dependency or an array of dependencies
53
53
  * which trigger a re-render when changed.
54
+ * @deprecated Add content elements as children of the popover using default slot
54
55
  */
55
56
  export declare function popoverRenderer(
56
57
  renderer: PopoverLitRenderer,
@@ -32,7 +32,7 @@ export class PopoverRendererDirective extends LitRendererDirective {
32
32
  }
33
33
 
34
34
  /**
35
- * A Lit directive for populating the content of the `<vaadin-popover-overlay>` element.
35
+ * A Lit directive for populating the content of the `<vaadin-popover>` element.
36
36
  *
37
37
  * The directive accepts a renderer callback returning a Lit template and assigns it to the popover
38
38
  * via the `renderer` property. The renderer is called once to populate the content when assigned
@@ -56,5 +56,6 @@ export class PopoverRendererDirective extends LitRendererDirective {
56
56
  * @param renderer the renderer callback that returns a Lit template.
57
57
  * @param dependencies a single dependency or an array of dependencies
58
58
  * which trigger a re-render when changed.
59
+ * @deprecated Add content elements as children of the popover using default slot
59
60
  */
60
61
  export const popoverRenderer = directive(PopoverRendererDirective);
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2024 - 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 popoverOverlayStyles: CSSResult;
@@ -0,0 +1,211 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2024 - 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
+ import { overlayStyles } from '@vaadin/overlay/src/styles/vaadin-overlay-base-styles.js';
8
+
9
+ const popoverOverlay = css`
10
+ :host {
11
+ --_arrow-size: var(--vaadin-popover-arrow-size, 8px);
12
+ --_default-offset: 4px;
13
+ --_rtl-multiplier: 1;
14
+ --_border-width: var(--vaadin-popover-border-width, var(--vaadin-overlay-border-width, 1px));
15
+ }
16
+
17
+ [part='overlay']:focus-visible {
18
+ outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
19
+ }
20
+
21
+ :host([dir='rtl']) {
22
+ --_rtl-multiplier: -1;
23
+ }
24
+
25
+ :host([modeless][with-backdrop]) [part='backdrop'] {
26
+ pointer-events: none;
27
+ }
28
+
29
+ :host([position^='top'][top-aligned]) [part='overlay'],
30
+ :host([position^='bottom'][top-aligned]) [part='overlay'] {
31
+ margin-top: var(--vaadin-popover-offset-top, var(--_default-offset));
32
+ }
33
+
34
+ [part='overlay'] {
35
+ position: relative;
36
+ overflow: visible;
37
+ max-height: 100%;
38
+ border: var(--_border-width) solid
39
+ var(--vaadin-popover-border-color, var(--vaadin-overlay-border-color, var(--vaadin-border-color-secondary)));
40
+ background: var(--vaadin-popover-background, var(--vaadin-overlay-background, var(--vaadin-background-color)));
41
+ box-shadow: var(--vaadin-popover-box-shadow, var(--vaadin-overlay-box-shadow, 0 8px 24px -4px rgba(0, 0, 0, 0.3)));
42
+ border-radius: var(--vaadin-popover-border-radius, var(--vaadin-overlay-border-radius, var(--vaadin-radius-m)));
43
+ }
44
+
45
+ [part='content'] {
46
+ overflow: auto;
47
+ overscroll-behavior: contain;
48
+ box-sizing: border-box;
49
+ max-height: 100%;
50
+ padding: var(--vaadin-popover-padding, var(--vaadin-padding-s));
51
+ }
52
+
53
+ :host([theme~='no-padding']) [part='content'] {
54
+ padding: 0 !important;
55
+ }
56
+
57
+ /* Increase the area of the popover so the pointer can go from the target directly to it. */
58
+ [part='overlay']::before {
59
+ position: absolute;
60
+ content: '';
61
+ inset-block: calc(var(--vaadin-popover-offset-top, var(--_default-offset)) * -1)
62
+ calc(var(--vaadin-popover-offset-bottom, var(--_default-offset)) * -1);
63
+ inset-inline: calc(var(--vaadin-popover-offset-start, var(--_default-offset)) * -1)
64
+ calc(var(--vaadin-popover-offset-end, var(--_default-offset)) * -1);
65
+ z-index: -1;
66
+ pointer-events: auto;
67
+ }
68
+
69
+ :host([position^='top'][bottom-aligned]) [part='overlay'],
70
+ :host([position^='bottom'][bottom-aligned]) [part='overlay'] {
71
+ margin-bottom: var(--vaadin-popover-offset-bottom, var(--_default-offset));
72
+ }
73
+
74
+ :host([position^='start'][start-aligned]) [part='overlay'],
75
+ :host([position^='end'][start-aligned]) [part='overlay'] {
76
+ margin-inline-start: var(--vaadin-popover-offset-start, var(--_default-offset));
77
+ }
78
+
79
+ :host([position^='start'][end-aligned]) [part='overlay'],
80
+ :host([position^='end'][end-aligned]) [part='overlay'] {
81
+ margin-inline-end: var(--vaadin-popover-offset-end, var(--_default-offset));
82
+ }
83
+
84
+ [part='arrow'] {
85
+ display: none;
86
+ }
87
+
88
+ :host([theme~='arrow']) {
89
+ --_default-offset: var(--_arrow-size);
90
+ }
91
+
92
+ :host([theme~='arrow']) [part='arrow'] {
93
+ display: block;
94
+ position: absolute;
95
+ background: inherit;
96
+ border: inherit;
97
+ border-start-start-radius: var(--vaadin-popover-arrow-border-radius, 0);
98
+ outline: inherit;
99
+ box-shadow: inherit;
100
+ width: var(--_arrow-size);
101
+ height: var(--_arrow-size);
102
+ rotate: 45deg;
103
+ --o: 20px; /* clip-path outset, how far outward it extends to reveal the outline and box shadow */
104
+ --b: var(--_border-width);
105
+ /* We need this elaborate clip-path to allow the arrow bg and border to cover
106
+ the overlay border but prevent the outline and box-shadow from covering it */
107
+ clip-path: polygon(
108
+ calc(var(--o) * -1) calc(var(--o) * -1),
109
+ calc(100% + var(--o) - var(--b)) calc(var(--o) * -1),
110
+ calc(100% - var(--b) * 1.4) 0,
111
+ 100% 0,
112
+ calc(100% - var(--b)) var(--b),
113
+ calc(100% - var(--b)) calc(var(--b) + var(--ff, 0px)),
114
+ calc(var(--b) + var(--ff, 0px)) calc(100% - var(--b)),
115
+ calc(var(--b)) calc(100% - var(--b)),
116
+ 0 100%,
117
+ 0 calc(100% - var(--b) * 1.4),
118
+ calc(var(--o) * -1) calc(100% + var(--o) - var(--b))
119
+ );
120
+ }
121
+
122
+ /* Firefox renders a blurry edge for a diagonal clip-path + rotation,
123
+ so we need to extend the clip-path slightly further on the diagonal */
124
+ @supports (-moz-appearance: none) {
125
+ :host([theme~='arrow']) [part='arrow'] {
126
+ --ff: 1px;
127
+ }
128
+ }
129
+
130
+ /* bottom / top */
131
+ :host([theme~='arrow']:is([position^='bottom'], [position^='top'])[start-aligned]) [part='arrow'] {
132
+ inset-inline-start: calc(var(--_arrow-size) * 2);
133
+ }
134
+
135
+ :host([theme~='arrow']:is([position^='bottom'], [position^='top'])[end-aligned]) [part='arrow'] {
136
+ inset-inline-end: calc(var(--_arrow-size) * 2);
137
+ }
138
+
139
+ :host([theme~='arrow']:is([position^='bottom'], [position^='top'])[arrow-centered]) [part='arrow'] {
140
+ inset-inline-start: 50%;
141
+ }
142
+
143
+ /* bottom */
144
+ :host([theme~='arrow']:is([position^='bottom'], [position^='top'])[top-aligned]) [part='arrow'] {
145
+ top: 0;
146
+ translate: calc(-50% * var(--_rtl-multiplier)) -50%;
147
+ }
148
+
149
+ :host([theme~='arrow']:is([position^='bottom'], [position^='top'])[end-aligned][top-aligned]) [part='arrow'] {
150
+ translate: calc(50% * var(--_rtl-multiplier)) -50%;
151
+ }
152
+
153
+ /* top */
154
+ :host([theme~='arrow']:is([position^='bottom'], [position^='top'])[bottom-aligned]) [part='arrow'] {
155
+ bottom: 0;
156
+ rotate: 225deg;
157
+ translate: calc(-50% * var(--_rtl-multiplier)) 50%;
158
+ }
159
+
160
+ :host([theme~='arrow']:is([position^='bottom'], [position^='top'])[end-aligned][bottom-aligned]) [part='arrow'] {
161
+ translate: calc(50% * var(--_rtl-multiplier)) 50%;
162
+ }
163
+
164
+ /* start / end */
165
+ :host([theme~='arrow']:is([position^='start'], [position^='end'])[top-aligned]) [part='arrow'] {
166
+ rotate: -45deg;
167
+ top: calc(var(--_arrow-size) * 2);
168
+ }
169
+
170
+ :host([theme~='arrow']:is([position^='start'], [position^='end'])[bottom-aligned]) [part='arrow'] {
171
+ rotate: -45deg;
172
+ bottom: calc(var(--_arrow-size) * 2);
173
+ }
174
+
175
+ :host([theme~='arrow']:is([position='start'], [position='end'])[top-aligned]) [part='arrow'] {
176
+ top: 50%;
177
+ }
178
+
179
+ :host([dir='rtl'][theme~='arrow']:is([position^='start'], [position^='end'])) [part='arrow'] {
180
+ scale: -1;
181
+ }
182
+
183
+ /* end */
184
+ :host([theme~='arrow']:is([position^='start'], [position^='end'])[start-aligned]) [part='arrow'] {
185
+ inset-inline-start: 0;
186
+ translate: calc(-50% * var(--_rtl-multiplier)) -50%;
187
+ }
188
+
189
+ :host([theme~='arrow']:is([position^='start'], [position^='end'])[start-aligned][bottom-aligned]) [part='arrow'] {
190
+ translate: calc(-50% * var(--_rtl-multiplier)) 50%;
191
+ }
192
+
193
+ /* start */
194
+ :host([theme~='arrow']:is([position^='start'], [position^='end'])[end-aligned]) [part='arrow'] {
195
+ rotate: 135deg;
196
+ inset-inline-end: 0;
197
+ translate: calc(50% * var(--_rtl-multiplier)) -50%;
198
+ }
199
+
200
+ :host([theme~='arrow']:is([position^='start'], [position^='end'])[end-aligned][bottom-aligned]) [part='arrow'] {
201
+ translate: calc(50% * var(--_rtl-multiplier)) 50%;
202
+ }
203
+
204
+ @media (forced-colors: active) {
205
+ :host {
206
+ --_border-width: 3px;
207
+ }
208
+ }
209
+ `;
210
+
211
+ export const popoverOverlayStyles = [overlayStyles, popoverOverlay];
@@ -5,26 +5,6 @@
5
5
  */
6
6
  import { OverlayMixin } from '@vaadin/overlay/src/vaadin-overlay-mixin.js';
7
7
  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
- };
28
8
 
29
9
  /**
30
10
  * A mixin providing common popover overlay functionality.
@@ -44,34 +24,6 @@ export const PopoverOverlayMixin = (superClass) =>
44
24
  };
45
25
  }
46
26
 
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
-
60
- requestContentUpdate() {
61
- super.requestContentUpdate();
62
-
63
- // Copy custom properties from the owner
64
- if (this.positionTarget && this.owner) {
65
- const style = getComputedStyle(this.owner);
66
- ['top', 'bottom', 'start', 'end'].forEach((prop) => {
67
- this.style.setProperty(
68
- `--${this._tagNamePrefix}-offset-${prop}`,
69
- style.getPropertyValue(`--${this._tagNamePrefix}-offset-${prop}`),
70
- );
71
- });
72
- }
73
- }
74
-
75
27
  /**
76
28
  * @protected
77
29
  * @override
@@ -120,14 +72,4 @@ export const PopoverOverlayMixin = (superClass) =>
120
72
  this.style.top = `${overlayRect.top + offset}px`;
121
73
  }
122
74
  }
123
-
124
- /** @private */
125
- __openedOrTargetChanged(opened, target) {
126
- if (target) {
127
- const parent = getClosestOverlay(target);
128
- if (parent) {
129
- setNestedOverlay(parent, opened ? this : null);
130
- }
131
- }
132
- }
133
75
  };
@@ -3,12 +3,14 @@
3
3
  * Copyright (c) 2024 - 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, html, LitElement } from 'lit';
6
+ import { html, LitElement } from 'lit';
7
+ import { isElementFocused } from '@vaadin/a11y-base/src/focus-utils.js';
7
8
  import { defineCustomElement } from '@vaadin/component-base/src/define.js';
8
9
  import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
9
10
  import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
10
- import { overlayStyles } from '@vaadin/overlay/src/vaadin-overlay-styles.js';
11
+ import { LumoInjectionMixin } from '@vaadin/vaadin-themable-mixin/lumo-injection-mixin.js';
11
12
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
13
+ import { popoverOverlayStyles } from './styles/vaadin-popover-overlay-base-styles.js';
12
14
  import { PopoverOverlayMixin } from './vaadin-popover-overlay-mixin.js';
13
15
 
14
16
  /**
@@ -21,92 +23,90 @@ import { PopoverOverlayMixin } from './vaadin-popover-overlay-mixin.js';
21
23
  * @mixes ThemableMixin
22
24
  * @private
23
25
  */
24
- class PopoverOverlay extends PopoverOverlayMixin(DirMixin(ThemableMixin(PolylitMixin(LitElement)))) {
26
+ class PopoverOverlay extends PopoverOverlayMixin(
27
+ DirMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement)))),
28
+ ) {
25
29
  static get is() {
26
30
  return 'vaadin-popover-overlay';
27
31
  }
28
32
 
29
33
  static get styles() {
30
- return [
31
- overlayStyles,
32
- css`
33
- :host {
34
- --_vaadin-popover-content-width: auto;
35
- --_vaadin-popover-content-height: auto;
36
- }
37
-
38
- :host([modeless][with-backdrop]) [part='backdrop'] {
39
- pointer-events: none;
40
- }
41
-
42
- :host([position^='top'][top-aligned]) [part='overlay'],
43
- :host([position^='bottom'][top-aligned]) [part='overlay'] {
44
- margin-top: var(--vaadin-popover-offset-top, 0);
45
- }
46
-
47
- [part='overlay'] {
48
- position: relative;
49
- overflow: visible;
50
- max-height: 100%;
51
- }
52
-
53
- [part='content'] {
54
- overflow: auto;
55
- box-sizing: border-box;
56
- max-height: 100%;
57
- width: var(--_vaadin-popover-content-width);
58
- height: var(--_vaadin-popover-content-height);
59
- }
60
-
61
- /* Increase the area of the popover so the pointer can go from the target directly to it. */
62
- [part='overlay']::before {
63
- position: absolute;
64
- content: '';
65
- inset-block: calc(var(--vaadin-popover-offset-top, 0) * -1) calc(var(--vaadin-popover-offset-bottom, 0) * -1);
66
- inset-inline: calc(var(--vaadin-popover-offset-start, 0) * -1) calc(var(--vaadin-popover-offset-end, 0) * -1);
67
- z-index: -1;
68
- pointer-events: auto;
69
- }
70
-
71
- :host([position^='top'][bottom-aligned]) [part='overlay'],
72
- :host([position^='bottom'][bottom-aligned]) [part='overlay'] {
73
- margin-bottom: var(--vaadin-popover-offset-bottom, 0);
74
- }
75
-
76
- :host([position^='start'][start-aligned]) [part='overlay'],
77
- :host([position^='end'][start-aligned]) [part='overlay'] {
78
- margin-inline-start: var(--vaadin-popover-offset-start, 0);
79
- }
80
-
81
- :host([position^='start'][end-aligned]) [part='overlay'],
82
- :host([position^='end'][end-aligned]) [part='overlay'] {
83
- margin-inline-end: var(--vaadin-popover-offset-end, 0);
84
- }
85
-
86
- [part='arrow'] {
87
- display: none;
88
- position: absolute;
89
- height: 0;
90
- width: 0;
91
- }
34
+ return popoverOverlayStyles;
35
+ }
92
36
 
93
- :host([theme~='arrow']) [part='arrow'] {
94
- display: block;
95
- }
96
- `,
97
- ];
37
+ static get lumoInjector() {
38
+ return {
39
+ includeBaseStyles: true,
40
+ };
98
41
  }
99
42
 
100
43
  /** @protected */
101
44
  render() {
102
45
  return html`
103
46
  <div id="backdrop" part="backdrop" hidden ?hidden="${!this.withBackdrop}"></div>
104
- <div part="overlay" id="overlay" tabindex="0">
47
+ <div part="overlay" id="overlay">
105
48
  <div part="arrow"></div>
106
49
  <div part="content" id="content"><slot></slot></div>
107
50
  </div>
108
51
  `;
109
52
  }
53
+
54
+ /** @protected */
55
+ updated(props) {
56
+ super.updated(props);
57
+
58
+ if (props.has('restoreFocusNode') && this.opened) {
59
+ // Save focus to be restored when target is set while opened
60
+ if (this.restoreFocusNode && isElementFocused(this.restoreFocusNode.focusElement || this.restoreFocusNode)) {
61
+ this.__focusRestorationController.saveFocus();
62
+ } else if (!this.restoreFocusNode) {
63
+ // Do not restore focus when target is cleared while opened
64
+ this.__focusRestorationController.focusNode = null;
65
+ }
66
+ }
67
+ }
68
+
69
+ /**
70
+ * @override
71
+ * @protected
72
+ */
73
+ get _contentRoot() {
74
+ return this.owner;
75
+ }
76
+
77
+ /**
78
+ * Override method from OverlayFocusMixin to use owner as focus trap root
79
+ * @protected
80
+ * @override
81
+ */
82
+ get _focusTrapRoot() {
83
+ return this.owner;
84
+ }
85
+
86
+ /**
87
+ * Override method from `OverlayMixin` to always add outside
88
+ * click listener so that it can be used by modeless popover.
89
+ * @return {boolean}
90
+ * @protected
91
+ * @override
92
+ */
93
+ _shouldAddGlobalListeners() {
94
+ return true;
95
+ }
96
+
97
+ /**
98
+ * Override method from `OverlayMixin` to prevent closing when clicking on target.
99
+ * Clicking the target will already close the popover when using the click trigger.
100
+ *
101
+ * @override
102
+ * @protected
103
+ */
104
+ _shouldCloseOnOutsideClick(event) {
105
+ if (event.composedPath().includes(this.positionTarget)) {
106
+ return false;
107
+ }
108
+ return super._shouldCloseOnOutsideClick(event);
109
+ }
110
110
  }
111
111
 
112
112
  defineCustomElement(PopoverOverlay);