@vaadin/overlay 25.0.0-alpha7 → 25.0.0-alpha8
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 +8 -8
- package/src/styles/vaadin-overlay-base-styles.js +61 -56
- package/src/styles/vaadin-overlay-core-styles.js +8 -0
- package/src/vaadin-overlay-focus-mixin.js +23 -5
- package/src/vaadin-overlay-mixin.js +30 -12
- package/src/vaadin-overlay-position-mixin.js +5 -5
- package/src/vaadin-overlay-stack-mixin.js +66 -5
- package/src/vaadin-overlay-utils.d.ts +6 -0
- package/src/vaadin-overlay-utils.js +29 -0
- package/src/vaadin-overlay.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/overlay",
|
|
3
|
-
"version": "25.0.0-
|
|
3
|
+
"version": "25.0.0-alpha8",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -36,17 +36,17 @@
|
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@open-wc/dedupe-mixin": "^1.3.0",
|
|
39
|
-
"@vaadin/a11y-base": "25.0.0-
|
|
40
|
-
"@vaadin/component-base": "25.0.0-
|
|
41
|
-
"@vaadin/vaadin-lumo-styles": "25.0.0-
|
|
42
|
-
"@vaadin/vaadin-themable-mixin": "25.0.0-
|
|
39
|
+
"@vaadin/a11y-base": "25.0.0-alpha8",
|
|
40
|
+
"@vaadin/component-base": "25.0.0-alpha8",
|
|
41
|
+
"@vaadin/vaadin-lumo-styles": "25.0.0-alpha8",
|
|
42
|
+
"@vaadin/vaadin-themable-mixin": "25.0.0-alpha8",
|
|
43
43
|
"lit": "^3.0.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@vaadin/chai-plugins": "25.0.0-
|
|
47
|
-
"@vaadin/test-runner-commands": "25.0.0-
|
|
46
|
+
"@vaadin/chai-plugins": "25.0.0-alpha8",
|
|
47
|
+
"@vaadin/test-runner-commands": "25.0.0-alpha8",
|
|
48
48
|
"@vaadin/testing-helpers": "^2.0.0",
|
|
49
49
|
"sinon": "^18.0.0"
|
|
50
50
|
},
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "ebf53673d5f639d2b1b6f2b31f640f530643ee2f"
|
|
52
52
|
}
|
|
@@ -7,76 +7,81 @@ import '@vaadin/component-base/src/style-props.js';
|
|
|
7
7
|
import { css } from 'lit';
|
|
8
8
|
|
|
9
9
|
export const overlayStyles = css`
|
|
10
|
-
|
|
11
|
-
:
|
|
12
|
-
|
|
13
|
-
position: fixed;
|
|
10
|
+
:host {
|
|
11
|
+
z-index: 200;
|
|
12
|
+
position: fixed;
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
/* Despite of what the names say, <vaadin-overlay> is just a container
|
|
16
15
|
for position/sizing/alignment. The actual overlay is the overlay part. */
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
/* Default position constraints. Themes can
|
|
19
18
|
override this to adjust the gap between the overlay and the viewport. */
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
inset: 8px;
|
|
20
|
+
bottom: var(--vaadin-overlay-viewport-bottom);
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
/* Override native [popover] user agent styles */
|
|
23
|
+
width: auto;
|
|
24
|
+
height: auto;
|
|
25
|
+
border: none;
|
|
26
|
+
padding: 0;
|
|
27
|
+
background-color: transparent;
|
|
28
|
+
overflow: visible;
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
/* Use flexbox alignment for the overlay part. */
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-direction: column; /* makes dropdowns sizing easier */
|
|
33
|
+
/* Align to center by default. */
|
|
34
|
+
align-items: center;
|
|
35
|
+
justify-content: center;
|
|
32
36
|
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
/* Allow centering when max-width/max-height applies. */
|
|
38
|
+
margin: auto;
|
|
35
39
|
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
/* The host is not clickable, only the overlay part is. */
|
|
41
|
+
pointer-events: none;
|
|
38
42
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
43
|
+
/* Remove tap highlight on touch devices. */
|
|
44
|
+
-webkit-tap-highlight-color: transparent;
|
|
42
45
|
|
|
43
|
-
|
|
44
|
-
:
|
|
45
|
-
|
|
46
|
-
display: none !important;
|
|
47
|
-
}
|
|
46
|
+
/* CSS API for host */
|
|
47
|
+
--vaadin-overlay-viewport-bottom: 8px;
|
|
48
|
+
}
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
box-sizing: border-box;
|
|
55
|
-
max-width: 100%;
|
|
56
|
-
overflow: auto;
|
|
57
|
-
overscroll-behavior: contain;
|
|
58
|
-
pointer-events: auto;
|
|
59
|
-
-webkit-tap-highlight-color: initial;
|
|
60
|
-
}
|
|
50
|
+
:host([hidden]),
|
|
51
|
+
:host(:not([opened]):not([closing])),
|
|
52
|
+
:host(:not([opened]):not([closing])) [part='overlay'] {
|
|
53
|
+
display: none !important;
|
|
54
|
+
}
|
|
61
55
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
56
|
+
[part='overlay'] {
|
|
57
|
+
background: var(--vaadin-overlay-background, var(--vaadin-background-color));
|
|
58
|
+
border: var(--vaadin-overlay-border-width, 1px) solid var(--vaadin-overlay-border-color, var(--vaadin-border-color));
|
|
59
|
+
border-radius: var(--vaadin-overlay-border-radius, var(--vaadin-radius-m));
|
|
60
|
+
box-shadow: var(--vaadin-overlay-box-shadow, 0 8px 24px -4px rgba(0, 0, 0, 0.3));
|
|
61
|
+
box-sizing: border-box;
|
|
62
|
+
max-width: 100%;
|
|
63
|
+
overflow: auto;
|
|
64
|
+
overscroll-behavior: contain;
|
|
65
|
+
pointer-events: auto;
|
|
66
|
+
-webkit-tap-highlight-color: initial;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
[part='backdrop'] {
|
|
70
|
+
background: var(--vaadin-overlay-backdrop-background, rgba(0, 0, 0, 0.5));
|
|
71
|
+
content: '';
|
|
72
|
+
inset: 0;
|
|
73
|
+
pointer-events: auto;
|
|
74
|
+
position: fixed;
|
|
75
|
+
z-index: -1;
|
|
76
|
+
}
|
|
70
77
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
78
|
+
[part='overlay']:focus-visible {
|
|
79
|
+
outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
|
|
80
|
+
}
|
|
75
81
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
82
|
+
@media (forced-colors: active) {
|
|
83
|
+
[part='overlay'] {
|
|
84
|
+
border: 3px solid;
|
|
80
85
|
}
|
|
81
86
|
}
|
|
82
87
|
`;
|
|
@@ -18,6 +18,14 @@ export const overlayStyles = css`
|
|
|
18
18
|
inset: 0;
|
|
19
19
|
bottom: var(--vaadin-overlay-viewport-bottom);
|
|
20
20
|
|
|
21
|
+
/* Override native [popover] user agent styles */
|
|
22
|
+
width: auto;
|
|
23
|
+
height: auto;
|
|
24
|
+
border: none;
|
|
25
|
+
padding: 0;
|
|
26
|
+
background-color: transparent;
|
|
27
|
+
overflow: visible;
|
|
28
|
+
|
|
21
29
|
/* Use flexbox alignment for the overlay part. */
|
|
22
30
|
display: flex;
|
|
23
31
|
flex-direction: column; /* makes dropdowns sizing easier */
|
|
@@ -48,11 +48,20 @@ export const OverlayFocusMixin = (superClass) =>
|
|
|
48
48
|
constructor() {
|
|
49
49
|
super();
|
|
50
50
|
|
|
51
|
-
this.__ariaModalController = new AriaModalController(this);
|
|
51
|
+
this.__ariaModalController = new AriaModalController(this, () => this._modalRoot);
|
|
52
52
|
this.__focusTrapController = new FocusTrapController(this);
|
|
53
53
|
this.__focusRestorationController = new FocusRestorationController();
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Override to specify another element used as a content root,
|
|
58
|
+
* e.g. slotted into the overlay, rather than overlay itself.
|
|
59
|
+
* @protected
|
|
60
|
+
*/
|
|
61
|
+
get _contentRoot() {
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
|
|
56
65
|
/** @protected */
|
|
57
66
|
ready() {
|
|
58
67
|
super.ready();
|
|
@@ -62,6 +71,15 @@ export const OverlayFocusMixin = (superClass) =>
|
|
|
62
71
|
this.addController(this.__focusRestorationController);
|
|
63
72
|
}
|
|
64
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Override to specify another element used as a modality root,
|
|
76
|
+
* e.g. the overlay's owner element, rather than overlay itself.
|
|
77
|
+
* @protected
|
|
78
|
+
*/
|
|
79
|
+
get _modalRoot() {
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
82
|
+
|
|
65
83
|
/**
|
|
66
84
|
* Release focus and restore focus after the overlay is closed.
|
|
67
85
|
*
|
|
@@ -127,15 +145,15 @@ export const OverlayFocusMixin = (superClass) =>
|
|
|
127
145
|
* @protected
|
|
128
146
|
*/
|
|
129
147
|
_deepContains(node) {
|
|
130
|
-
if (this.contains(node)) {
|
|
148
|
+
if (this._contentRoot.contains(node)) {
|
|
131
149
|
return true;
|
|
132
150
|
}
|
|
133
151
|
let n = node;
|
|
134
152
|
const doc = node.ownerDocument;
|
|
135
|
-
// Walk from node to
|
|
136
|
-
while (n && n !== doc && n !== this) {
|
|
153
|
+
// Walk from node to content root or `document`
|
|
154
|
+
while (n && n !== doc && n !== this._contentRoot) {
|
|
137
155
|
n = n.parentNode || n.host;
|
|
138
156
|
}
|
|
139
|
-
return n === this;
|
|
157
|
+
return n === this._contentRoot;
|
|
140
158
|
}
|
|
141
159
|
};
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { isIOS } from '@vaadin/component-base/src/browser-utils.js';
|
|
7
7
|
import { OverlayFocusMixin } from './vaadin-overlay-focus-mixin.js';
|
|
8
8
|
import { OverlayStackMixin } from './vaadin-overlay-stack-mixin.js';
|
|
9
|
+
import { setOverlayStateAttribute } from './vaadin-overlay-utils.js';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* @polymerMixin
|
|
@@ -91,6 +92,7 @@ export const OverlayMixin = (superClass) =>
|
|
|
91
92
|
type: Boolean,
|
|
92
93
|
value: false,
|
|
93
94
|
reflectToAttribute: true,
|
|
95
|
+
observer: '_withBackdropChanged',
|
|
94
96
|
sync: true,
|
|
95
97
|
},
|
|
96
98
|
};
|
|
@@ -123,7 +125,9 @@ export const OverlayMixin = (superClass) =>
|
|
|
123
125
|
// get invoked on iOS Safari (reproducible in <vaadin-dialog>
|
|
124
126
|
// and <vaadin-context-menu>).
|
|
125
127
|
this.addEventListener('click', () => {});
|
|
126
|
-
this.$.backdrop
|
|
128
|
+
if (this.$.backdrop) {
|
|
129
|
+
this.$.backdrop.addEventListener('click', () => {});
|
|
130
|
+
}
|
|
127
131
|
|
|
128
132
|
this.addEventListener('mouseup', () => {
|
|
129
133
|
// In Chrome, focus moves to body on overlay content mousedown
|
|
@@ -163,7 +167,7 @@ export const OverlayMixin = (superClass) =>
|
|
|
163
167
|
*/
|
|
164
168
|
requestContentUpdate() {
|
|
165
169
|
if (this.renderer) {
|
|
166
|
-
this.renderer.call(this.owner, this, this.owner, this.model);
|
|
170
|
+
this.renderer.call(this.owner, this._contentRoot, this.owner, this.model);
|
|
167
171
|
}
|
|
168
172
|
}
|
|
169
173
|
|
|
@@ -256,11 +260,11 @@ export const OverlayMixin = (superClass) =>
|
|
|
256
260
|
this._oldOpened = opened;
|
|
257
261
|
|
|
258
262
|
if (rendererChanged && hasOldRenderer) {
|
|
259
|
-
this.innerHTML = '';
|
|
263
|
+
this._contentRoot.innerHTML = '';
|
|
260
264
|
// Whenever a Lit-based renderer is used, it assigns a Lit part to the node it was rendered into.
|
|
261
265
|
// When clearing the rendered content, this part needs to be manually disposed of.
|
|
262
266
|
// Otherwise, using a Lit-based renderer on the same node will throw an exception or render nothing afterward.
|
|
263
|
-
delete this._$litPart$;
|
|
267
|
+
delete this._contentRoot._$litPart$;
|
|
264
268
|
}
|
|
265
269
|
|
|
266
270
|
if (opened && renderer && (rendererChanged || openedChanged || ownerOrModelChanged)) {
|
|
@@ -279,11 +283,23 @@ export const OverlayMixin = (superClass) =>
|
|
|
279
283
|
this._removeGlobalListeners();
|
|
280
284
|
this._exitModalState();
|
|
281
285
|
}
|
|
286
|
+
setOverlayStateAttribute(this, 'modeless', modeless);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** @private */
|
|
290
|
+
_withBackdropChanged(withBackdrop) {
|
|
291
|
+
setOverlayStateAttribute(this, 'with-backdrop', withBackdrop);
|
|
282
292
|
}
|
|
283
293
|
|
|
284
294
|
/** @private */
|
|
285
295
|
_openedChanged(opened, wasOpened) {
|
|
286
296
|
if (opened) {
|
|
297
|
+
// Prevent possible errors on setting `opened` to `true` while disconnected
|
|
298
|
+
if (!this.isConnected) {
|
|
299
|
+
this.opened = false;
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
|
|
287
303
|
this._saveFocus();
|
|
288
304
|
|
|
289
305
|
this._animatedOpening();
|
|
@@ -292,7 +308,7 @@ export const OverlayMixin = (superClass) =>
|
|
|
292
308
|
setTimeout(() => {
|
|
293
309
|
this._trapFocus();
|
|
294
310
|
|
|
295
|
-
this.dispatchEvent(new CustomEvent('vaadin-overlay-open', { bubbles: true }));
|
|
311
|
+
this.dispatchEvent(new CustomEvent('vaadin-overlay-open', { bubbles: true, composed: true }));
|
|
296
312
|
});
|
|
297
313
|
});
|
|
298
314
|
|
|
@@ -369,14 +385,16 @@ export const OverlayMixin = (superClass) =>
|
|
|
369
385
|
|
|
370
386
|
/** @private */
|
|
371
387
|
_animatedOpening() {
|
|
372
|
-
if (this.
|
|
388
|
+
if (this._isAttached && this.hasAttribute('closing')) {
|
|
373
389
|
this._flushAnimation('closing');
|
|
374
390
|
}
|
|
375
391
|
this._attachOverlay();
|
|
392
|
+
this._appendAttachedInstance();
|
|
393
|
+
this.bringToFront();
|
|
376
394
|
if (!this.modeless) {
|
|
377
395
|
this._enterModalState();
|
|
378
396
|
}
|
|
379
|
-
this
|
|
397
|
+
setOverlayStateAttribute(this, 'opening', true);
|
|
380
398
|
|
|
381
399
|
if (this._shouldAnimate()) {
|
|
382
400
|
this._enqueueAnimation('opening', () => {
|
|
@@ -392,19 +410,19 @@ export const OverlayMixin = (superClass) =>
|
|
|
392
410
|
this._placeholder = document.createComment('vaadin-overlay-placeholder');
|
|
393
411
|
this.parentNode.insertBefore(this._placeholder, this);
|
|
394
412
|
document.body.appendChild(this);
|
|
395
|
-
this.bringToFront();
|
|
396
413
|
}
|
|
397
414
|
|
|
398
415
|
/** @private */
|
|
399
416
|
_finishOpening() {
|
|
400
|
-
this
|
|
417
|
+
setOverlayStateAttribute(this, 'opening', false);
|
|
401
418
|
}
|
|
402
419
|
|
|
403
420
|
/** @private */
|
|
404
421
|
_finishClosing() {
|
|
405
422
|
this._detachOverlay();
|
|
423
|
+
this._removeAttachedInstance();
|
|
406
424
|
this.$.overlay.style.removeProperty('pointer-events');
|
|
407
|
-
this
|
|
425
|
+
setOverlayStateAttribute(this, 'closing', false);
|
|
408
426
|
this.dispatchEvent(new CustomEvent('vaadin-overlay-closed'));
|
|
409
427
|
}
|
|
410
428
|
|
|
@@ -413,9 +431,9 @@ export const OverlayMixin = (superClass) =>
|
|
|
413
431
|
if (this.hasAttribute('opening')) {
|
|
414
432
|
this._flushAnimation('opening');
|
|
415
433
|
}
|
|
416
|
-
if (this.
|
|
434
|
+
if (this._isAttached) {
|
|
417
435
|
this._exitModalState();
|
|
418
|
-
this
|
|
436
|
+
setOverlayStateAttribute(this, 'closing', true);
|
|
419
437
|
this.dispatchEvent(new CustomEvent('vaadin-overlay-closing'));
|
|
420
438
|
|
|
421
439
|
if (this._shouldAnimate()) {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
6
|
import { getAncestorRootNodes } from '@vaadin/component-base/src/dom-utils.js';
|
|
7
|
-
import { observeMove } from './vaadin-overlay-utils.js';
|
|
7
|
+
import { observeMove, setOverlayStateAttribute } from './vaadin-overlay-utils.js';
|
|
8
8
|
|
|
9
9
|
const PROP_NAMES_VERTICAL = {
|
|
10
10
|
start: 'top',
|
|
@@ -271,11 +271,11 @@ export const PositionMixin = (superClass) =>
|
|
|
271
271
|
// Apply the positioning properties to the overlay
|
|
272
272
|
Object.assign(this.style, verticalProps, horizontalProps);
|
|
273
273
|
|
|
274
|
-
this
|
|
275
|
-
this
|
|
274
|
+
setOverlayStateAttribute(this, 'bottom-aligned', !shouldAlignStartVertically);
|
|
275
|
+
setOverlayStateAttribute(this, 'top-aligned', shouldAlignStartVertically);
|
|
276
276
|
|
|
277
|
-
this
|
|
278
|
-
this
|
|
277
|
+
setOverlayStateAttribute(this, 'end-aligned', !flexStart);
|
|
278
|
+
setOverlayStateAttribute(this, 'start-aligned', flexStart);
|
|
279
279
|
}
|
|
280
280
|
|
|
281
281
|
__shouldAlignStartHorizontally(targetRect, rtl) {
|
|
@@ -4,14 +4,17 @@
|
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
/** @type {Set<HTMLElement>} */
|
|
8
|
+
const attachedInstances = new Set();
|
|
9
|
+
|
|
7
10
|
/**
|
|
8
11
|
* Returns all attached overlays in visual stacking order.
|
|
9
12
|
* @private
|
|
10
13
|
*/
|
|
11
14
|
const getAttachedInstances = () =>
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
[...attachedInstances].filter(
|
|
16
|
+
(el) => el instanceof HTMLElement && el._hasOverlayStackMixin && !el.hasAttribute('closing'),
|
|
17
|
+
);
|
|
15
18
|
|
|
16
19
|
/**
|
|
17
20
|
* Returns all attached overlay instances excluding notification container,
|
|
@@ -20,6 +23,24 @@ const getAttachedInstances = () =>
|
|
|
20
23
|
*/
|
|
21
24
|
const getOverlayInstances = () => getAttachedInstances().filter((el) => el.$.overlay);
|
|
22
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Returns true if all the instances on top of the overlay are nested overlays.
|
|
28
|
+
* @private
|
|
29
|
+
*/
|
|
30
|
+
const hasOnlyNestedOverlays = (overlay) => {
|
|
31
|
+
const instances = getAttachedInstances();
|
|
32
|
+
const next = instances[instances.indexOf(overlay) + 1];
|
|
33
|
+
if (!next) {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!overlay._deepContains(next)) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return hasOnlyNestedOverlays(next);
|
|
42
|
+
};
|
|
43
|
+
|
|
23
44
|
/**
|
|
24
45
|
* Returns true if the overlay is the last one in the opened overlays stack.
|
|
25
46
|
* @param {HTMLElement} overlay
|
|
@@ -70,20 +91,48 @@ export const OverlayStackMixin = (superClass) =>
|
|
|
70
91
|
return isLastOverlay(this);
|
|
71
92
|
}
|
|
72
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Returns true if this is overlay is attached.
|
|
96
|
+
*
|
|
97
|
+
* @return {boolean}
|
|
98
|
+
* @protected
|
|
99
|
+
*/
|
|
100
|
+
get _isAttached() {
|
|
101
|
+
return attachedInstances.has(this);
|
|
102
|
+
}
|
|
103
|
+
|
|
73
104
|
/**
|
|
74
105
|
* Brings the overlay as visually the frontmost one.
|
|
75
106
|
*/
|
|
76
107
|
bringToFront() {
|
|
108
|
+
// Update z-index to be the highest among all attached overlays
|
|
109
|
+
// TODO: Can be removed after switching all overlays to be based on native popover
|
|
77
110
|
let zIndex = '';
|
|
78
111
|
const frontmost = getAttachedInstances()
|
|
79
112
|
.filter((o) => o !== this)
|
|
80
113
|
.pop();
|
|
81
114
|
if (frontmost) {
|
|
82
|
-
const frontmostZIndex = frontmost.
|
|
115
|
+
const frontmostZIndex = parseFloat(getComputedStyle(frontmost).zIndex);
|
|
83
116
|
zIndex = frontmostZIndex + 1;
|
|
84
117
|
}
|
|
85
118
|
this.style.zIndex = zIndex;
|
|
86
|
-
|
|
119
|
+
|
|
120
|
+
// If the overlay is the last one, or if all other overlays shown above
|
|
121
|
+
// are nested overlays (e.g. date-picker inside a dialog), do not call
|
|
122
|
+
// `showPopover()` unnecessarily to avoid scroll position being reset.
|
|
123
|
+
if (isLastOverlay(this) || hasOnlyNestedOverlays(this)) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Update stacking order of native popover-based overlays
|
|
128
|
+
if (this.matches(':popover-open')) {
|
|
129
|
+
this.hidePopover();
|
|
130
|
+
this.showPopover();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Update order of attached instances
|
|
134
|
+
this._removeAttachedInstance();
|
|
135
|
+
this._appendAttachedInstance();
|
|
87
136
|
|
|
88
137
|
// If there is a nested overlay, call `bringToFront()` for it as well.
|
|
89
138
|
if (overlayMap.has(this)) {
|
|
@@ -133,4 +182,16 @@ export const OverlayStackMixin = (superClass) =>
|
|
|
133
182
|
}
|
|
134
183
|
}
|
|
135
184
|
}
|
|
185
|
+
|
|
186
|
+
/** @protected */
|
|
187
|
+
_appendAttachedInstance() {
|
|
188
|
+
attachedInstances.add(this);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** @protected */
|
|
192
|
+
_removeAttachedInstance() {
|
|
193
|
+
if (this._isAttached) {
|
|
194
|
+
attachedInstances.delete(this);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
136
197
|
};
|
|
@@ -11,3 +11,9 @@
|
|
|
11
11
|
* https://github.com/floating-ui/floating-ui/blob/58ed169/packages/dom/src/autoUpdate.ts#L45
|
|
12
12
|
*/
|
|
13
13
|
export function observeMove(element: HTMLElement, callback: () => void): () => void;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Toggle the state attribute on the overlay element and also its owner element. This allows targeting state attributes
|
|
17
|
+
* in the light DOM in case the overlay is in the shadow DOM of its owner.
|
|
18
|
+
*/
|
|
19
|
+
export function setOverlayStateAttribute(overlay: HTMLElement, name: string, value: string | boolean): void;
|
|
@@ -87,3 +87,32 @@ export function observeMove(element, callback) {
|
|
|
87
87
|
|
|
88
88
|
return cleanup;
|
|
89
89
|
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Toggle the state attribute on the overlay element and also its owner element. This allows targeting state attributes
|
|
93
|
+
* in the light DOM in case the overlay is in the shadow DOM of its owner.
|
|
94
|
+
* @param {HTMLElement} overlay The overlay element on which to toggle the attribute.
|
|
95
|
+
* @param {string} name The name of the attribute to toggle.
|
|
96
|
+
* @param {string|boolean} value The value of the attribute. If a string is provided, it will be set as the attribute
|
|
97
|
+
* value. Otherwise, the attribute will be added or removed depending on whether `value` is truthy or falsy.
|
|
98
|
+
*/
|
|
99
|
+
export function setOverlayStateAttribute(overlay, name, value) {
|
|
100
|
+
const elements = [overlay];
|
|
101
|
+
if (overlay.owner) {
|
|
102
|
+
elements.push(overlay.owner);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (typeof value === 'string') {
|
|
106
|
+
elements.forEach((element) => {
|
|
107
|
+
element.setAttribute(name, value);
|
|
108
|
+
});
|
|
109
|
+
} else if (value) {
|
|
110
|
+
elements.forEach((element) => {
|
|
111
|
+
element.setAttribute(name, '');
|
|
112
|
+
});
|
|
113
|
+
} else {
|
|
114
|
+
elements.forEach((element) => {
|
|
115
|
+
element.removeAttribute(name);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
package/src/vaadin-overlay.js
CHANGED
|
@@ -77,7 +77,7 @@ import { OverlayMixin } from './vaadin-overlay-mixin.js';
|
|
|
77
77
|
* @mixes DirMixin
|
|
78
78
|
* @mixes OverlayMixin
|
|
79
79
|
*/
|
|
80
|
-
class Overlay extends OverlayMixin(DirMixin(ThemableMixin(LumoInjectionMixin(
|
|
80
|
+
class Overlay extends OverlayMixin(DirMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
|
|
81
81
|
static get is() {
|
|
82
82
|
return 'vaadin-overlay';
|
|
83
83
|
}
|