@vaadin/overlay 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/overlay",
3
- "version": "25.0.0-alpha2",
3
+ "version": "25.0.0-alpha20",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -21,9 +21,6 @@
21
21
  "type": "module",
22
22
  "files": [
23
23
  "src",
24
- "!src/*-base-styles.d.ts",
25
- "!src/*-base-styles.js",
26
- "theme",
27
24
  "vaadin-*.d.ts",
28
25
  "vaadin-*.js"
29
26
  ],
@@ -36,17 +33,17 @@
36
33
  ],
37
34
  "dependencies": {
38
35
  "@open-wc/dedupe-mixin": "^1.3.0",
39
- "@vaadin/a11y-base": "25.0.0-alpha2",
40
- "@vaadin/component-base": "25.0.0-alpha2",
41
- "@vaadin/vaadin-lumo-styles": "25.0.0-alpha2",
42
- "@vaadin/vaadin-themable-mixin": "25.0.0-alpha2",
36
+ "@vaadin/a11y-base": "25.0.0-alpha20",
37
+ "@vaadin/component-base": "25.0.0-alpha20",
38
+ "@vaadin/vaadin-themable-mixin": "25.0.0-alpha20",
43
39
  "lit": "^3.0.0"
44
40
  },
45
41
  "devDependencies": {
46
- "@vaadin/chai-plugins": "25.0.0-alpha2",
47
- "@vaadin/test-runner-commands": "25.0.0-alpha2",
42
+ "@vaadin/chai-plugins": "25.0.0-alpha20",
43
+ "@vaadin/test-runner-commands": "25.0.0-alpha20",
48
44
  "@vaadin/testing-helpers": "^2.0.0",
49
- "sinon": "^18.0.0"
45
+ "@vaadin/vaadin-lumo-styles": "25.0.0-alpha20",
46
+ "sinon": "^21.0.0"
50
47
  },
51
- "gitHead": "67ffcd5355cf21ce1b5039c598525109fc4c164b"
48
+ "gitHead": "c948aae591a30b432f3784000d4677674cae56e0"
52
49
  }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2025 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import '@vaadin/component-base/src/styles/style-props.js';
7
+ import { css } from 'lit';
8
+
9
+ export const overlayStyles = css`
10
+ :host {
11
+ z-index: 200;
12
+ position: fixed;
13
+
14
+ /* Despite of what the names say, <vaadin-overlay> is just a container
15
+ for position/sizing/alignment. The actual overlay is the overlay part. */
16
+
17
+ /* Default position constraints. Themes can
18
+ override this to adjust the gap between the overlay and the viewport. */
19
+ inset: var(--vaadin-overlay-viewport-inset, 8px);
20
+ bottom: var(--vaadin-overlay-viewport-bottom);
21
+
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
+
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;
36
+
37
+ /* Allow centering when max-width/max-height applies. */
38
+ margin: auto;
39
+
40
+ /* The host is not clickable, only the overlay part is. */
41
+ pointer-events: none;
42
+
43
+ /* Remove tap highlight on touch devices. */
44
+ -webkit-tap-highlight-color: transparent;
45
+
46
+ /* CSS API for host */
47
+ --vaadin-overlay-viewport-bottom: 8px;
48
+ }
49
+
50
+ :host([hidden]),
51
+ :host(:not([opened]):not([closing])),
52
+ :host(:not([opened]):not([closing])) [part='overlay'] {
53
+ display: none !important;
54
+ }
55
+
56
+ [part='overlay'] {
57
+ background: var(--vaadin-overlay-background, var(--vaadin-background-color));
58
+ border: var(--vaadin-overlay-border-width, 1px) solid
59
+ var(--vaadin-overlay-border-color, var(--vaadin-border-color-secondary));
60
+ border-radius: var(--vaadin-overlay-border-radius, var(--vaadin-radius-m));
61
+ box-shadow: var(--vaadin-overlay-box-shadow, 0 8px 24px -4px rgba(0, 0, 0, 0.3));
62
+ box-sizing: border-box;
63
+ max-width: 100%;
64
+ overflow: auto;
65
+ overscroll-behavior: contain;
66
+ pointer-events: auto;
67
+ -webkit-tap-highlight-color: initial;
68
+
69
+ /* CSS reset for font styles */
70
+ color: initial;
71
+ font: initial;
72
+ letter-spacing: initial;
73
+ text-align: initial;
74
+ text-decoration: initial;
75
+ text-indent: initial;
76
+ text-transform: initial;
77
+ white-space: initial;
78
+ word-spacing: initial;
79
+ }
80
+
81
+ [part='backdrop'] {
82
+ background: var(--vaadin-overlay-backdrop-background, rgba(0, 0, 0, 0.2));
83
+ content: '';
84
+ inset: 0;
85
+ pointer-events: auto;
86
+ position: fixed;
87
+ z-index: -1;
88
+ }
89
+
90
+ [part='overlay']:focus-visible {
91
+ outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
92
+ }
93
+
94
+ @media (forced-colors: active) {
95
+ [part='overlay'] {
96
+ border: 3px solid !important;
97
+ }
98
+ }
99
+ `;
@@ -3,7 +3,6 @@
3
3
  * Copyright (c) 2017 - 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 { AriaModalController } from '@vaadin/a11y-base/src/aria-modal-controller.js';
7
6
  import { FocusRestorationController } from '@vaadin/a11y-base/src/focus-restoration-controller.js';
8
7
  import { FocusTrapController } from '@vaadin/a11y-base/src/focus-trap-controller.js';
9
8
  import { getDeepActiveElement, isKeyboardActive } from '@vaadin/a11y-base/src/focus-utils.js';
@@ -48,20 +47,36 @@ export const OverlayFocusMixin = (superClass) =>
48
47
  constructor() {
49
48
  super();
50
49
 
51
- this.__ariaModalController = new AriaModalController(this);
52
50
  this.__focusTrapController = new FocusTrapController(this);
53
51
  this.__focusRestorationController = new FocusRestorationController();
54
52
  }
55
53
 
54
+ /**
55
+ * Override to specify another element used as a content root,
56
+ * e.g. slotted into the overlay, rather than overlay itself.
57
+ * @protected
58
+ */
59
+ get _contentRoot() {
60
+ return this;
61
+ }
62
+
56
63
  /** @protected */
57
64
  ready() {
58
65
  super.ready();
59
66
 
60
- this.addController(this.__ariaModalController);
61
67
  this.addController(this.__focusTrapController);
62
68
  this.addController(this.__focusRestorationController);
63
69
  }
64
70
 
71
+ /**
72
+ * Override to specify another element used as a focus trap root,
73
+ * e.g. the overlay's owner element, rather than overlay part.
74
+ * @protected
75
+ */
76
+ get _focusTrapRoot() {
77
+ return this.$.overlay;
78
+ }
79
+
65
80
  /**
66
81
  * Release focus and restore focus after the overlay is closed.
67
82
  *
@@ -69,13 +84,13 @@ export const OverlayFocusMixin = (superClass) =>
69
84
  */
70
85
  _resetFocus() {
71
86
  if (this.focusTrap) {
72
- this.__ariaModalController.close();
73
87
  this.__focusTrapController.releaseFocus();
74
88
  }
75
89
 
76
90
  if (this.restoreFocusOnClose && this._shouldRestoreFocus()) {
77
- const preventScroll = !isKeyboardActive();
78
- this.__focusRestorationController.restoreFocus({ preventScroll });
91
+ const focusVisible = isKeyboardActive();
92
+ const preventScroll = !focusVisible;
93
+ this.__focusRestorationController.restoreFocus({ preventScroll, focusVisible });
79
94
  }
80
95
  }
81
96
 
@@ -97,8 +112,7 @@ export const OverlayFocusMixin = (superClass) =>
97
112
  */
98
113
  _trapFocus() {
99
114
  if (this.focusTrap) {
100
- this.__ariaModalController.showModal();
101
- this.__focusTrapController.trapFocus(this.$.overlay);
115
+ this.__focusTrapController.trapFocus(this._focusTrapRoot);
102
116
  }
103
117
  }
104
118
 
@@ -127,15 +141,15 @@ export const OverlayFocusMixin = (superClass) =>
127
141
  * @protected
128
142
  */
129
143
  _deepContains(node) {
130
- if (this.contains(node)) {
144
+ if (this._contentRoot.contains(node)) {
131
145
  return true;
132
146
  }
133
147
  let n = node;
134
148
  const doc = node.ownerDocument;
135
- // Walk from node to `this` or `document`
136
- while (n && n !== doc && n !== this) {
149
+ // Walk from node to content root or `document`
150
+ while (n && n !== doc && n !== this._contentRoot) {
137
151
  n = n.parentNode || n.host;
138
152
  }
139
- return n === this;
153
+ return n === this._contentRoot;
140
154
  }
141
155
  };
@@ -7,6 +7,13 @@ import type { Constructor } from '@open-wc/dedupe-mixin';
7
7
  import type { OverlayFocusMixinClass } from './vaadin-overlay-focus-mixin.js';
8
8
  import type { OverlayStackMixinClass } from './vaadin-overlay-stack-mixin.js';
9
9
 
10
+ export type OverlayBounds = {
11
+ top?: number | string;
12
+ left?: number | string;
13
+ width?: number | string;
14
+ height?: number | string;
15
+ };
16
+
10
17
  export type OverlayRenderer = (root: HTMLElement, owner: HTMLElement, model?: object) => void;
11
18
 
12
19
  export declare function OverlayMixin<T extends Constructor<HTMLElement>>(
@@ -58,6 +65,11 @@ export declare class OverlayMixinClass {
58
65
 
59
66
  close(sourceEvent?: Event | null): void;
60
67
 
68
+ /**
69
+ * Updates the coordinates of the overlay.
70
+ */
71
+ setBounds(bounds: OverlayBounds, absolute?: boolean): void;
72
+
61
73
  /**
62
74
  * Requests an update for the content of the overlay.
63
75
  * While performing the update, it invokes the renderer passed in the `renderer` property.
@@ -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
  };
@@ -115,15 +117,20 @@ export const OverlayMixin = (superClass) =>
115
117
  }
116
118
 
117
119
  /** @protected */
118
- ready() {
119
- super.ready();
120
+ firstUpdated() {
121
+ super.firstUpdated();
122
+
123
+ // Set popover in firstUpdated before opened observers are called
124
+ this.popover = 'manual';
120
125
 
121
126
  // Need to add dummy click listeners to this and the backdrop or else
122
127
  // the document click event listener (_outsideClickListener) may never
123
128
  // get invoked on iOS Safari (reproducible in <vaadin-dialog>
124
129
  // and <vaadin-context-menu>).
125
130
  this.addEventListener('click', () => {});
126
- this.$.backdrop.addEventListener('click', () => {});
131
+ if (this.$.backdrop) {
132
+ this.$.backdrop.addEventListener('click', () => {});
133
+ }
127
134
 
128
135
  this.addEventListener('mouseup', () => {
129
136
  // In Chrome, focus moves to body on overlay content mousedown
@@ -149,6 +156,11 @@ export const OverlayMixin = (superClass) =>
149
156
  disconnectedCallback() {
150
157
  super.disconnectedCallback();
151
158
 
159
+ if (this.__scheduledOpen) {
160
+ cancelAnimationFrame(this.__scheduledOpen);
161
+ this.__scheduledOpen = null;
162
+ }
163
+
152
164
  /* c8 ignore next 3 */
153
165
  if (this._boundIosResizeListener) {
154
166
  window.removeEventListener('resize', this._boundIosResizeListener);
@@ -163,7 +175,7 @@ export const OverlayMixin = (superClass) =>
163
175
  */
164
176
  requestContentUpdate() {
165
177
  if (this.renderer) {
166
- this.renderer.call(this.owner, this, this.owner, this.model);
178
+ this.renderer.call(this.owner, this._contentRoot, this.owner, this.model);
167
179
  }
168
180
  }
169
181
 
@@ -171,17 +183,44 @@ export const OverlayMixin = (superClass) =>
171
183
  * @param {Event=} sourceEvent
172
184
  */
173
185
  close(sourceEvent) {
174
- const evt = new CustomEvent('vaadin-overlay-close', {
186
+ // Dispatch the event on the overlay. Not using composed, as propagating the event through shadow roots could have
187
+ // side effects when nesting overlays
188
+ const event = new CustomEvent('vaadin-overlay-close', {
175
189
  bubbles: true,
176
190
  cancelable: true,
177
- detail: { sourceEvent },
191
+ detail: { overlay: this, sourceEvent },
178
192
  });
179
- this.dispatchEvent(evt);
180
- if (!evt.defaultPrevented) {
193
+ this.dispatchEvent(event);
194
+ // To allow listening for the event globally, also dispatch it on the document body
195
+ document.body.dispatchEvent(event);
196
+ if (!event.defaultPrevented) {
181
197
  this.opened = false;
182
198
  }
183
199
  }
184
200
 
201
+ /**
202
+ * Updates the coordinates of the overlay.
203
+ * @param {!OverlayBoundsParam} bounds
204
+ * @param {boolean} absolute
205
+ */
206
+ setBounds(bounds, absolute = true) {
207
+ const overlay = this.$.overlay;
208
+ const parsedBounds = { ...bounds };
209
+
210
+ if (absolute && overlay.style.position !== 'absolute') {
211
+ overlay.style.position = 'absolute';
212
+ }
213
+
214
+ Object.keys(parsedBounds).forEach((arg) => {
215
+ // Allow setting width or height to `null`
216
+ if (parsedBounds[arg] !== null && !isNaN(parsedBounds[arg])) {
217
+ parsedBounds[arg] = `${parsedBounds[arg]}px`;
218
+ }
219
+ });
220
+
221
+ Object.assign(overlay.style, parsedBounds);
222
+ }
223
+
185
224
  /** @private */
186
225
  _detectIosNavbar() {
187
226
  /* c8 ignore next 15 */
@@ -203,8 +242,25 @@ export const OverlayMixin = (superClass) =>
203
242
  }
204
243
  }
205
244
 
245
+ /**
246
+ * Whether to add global listeners for closing on outside click.
247
+ * By default, listeners are not added for a modeless overlay.
248
+ *
249
+ * @return {boolean}
250
+ * @protected
251
+ */
252
+ _shouldAddGlobalListeners() {
253
+ return !this.modeless;
254
+ }
255
+
206
256
  /** @private */
207
257
  _addGlobalListeners() {
258
+ if (this.__hasGlobalListeners) {
259
+ return;
260
+ }
261
+
262
+ this.__hasGlobalListeners = true;
263
+
208
264
  document.addEventListener('mousedown', this._boundMouseDownListener);
209
265
  document.addEventListener('mouseup', this._boundMouseUpListener);
210
266
  // Firefox leaks click to document on contextmenu even if prevented
@@ -214,6 +270,12 @@ export const OverlayMixin = (superClass) =>
214
270
 
215
271
  /** @private */
216
272
  _removeGlobalListeners() {
273
+ if (!this.__hasGlobalListeners) {
274
+ return;
275
+ }
276
+
277
+ this.__hasGlobalListeners = false;
278
+
217
279
  document.removeEventListener('mousedown', this._boundMouseDownListener);
218
280
  document.removeEventListener('mouseup', this._boundMouseUpListener);
219
281
  document.documentElement.removeEventListener('click', this._boundOutsideClickListener, true);
@@ -233,11 +295,11 @@ export const OverlayMixin = (superClass) =>
233
295
  this._oldOpened = opened;
234
296
 
235
297
  if (rendererChanged && hasOldRenderer) {
236
- this.innerHTML = '';
298
+ this._contentRoot.innerHTML = '';
237
299
  // Whenever a Lit-based renderer is used, it assigns a Lit part to the node it was rendered into.
238
300
  // When clearing the rendered content, this part needs to be manually disposed of.
239
301
  // Otherwise, using a Lit-based renderer on the same node will throw an exception or render nothing afterward.
240
- delete this._$litPart$;
302
+ delete this._contentRoot._$litPart$;
241
303
  }
242
304
 
243
305
  if (opened && renderer && (rendererChanged || openedChanged || ownerOrModelChanged)) {
@@ -247,20 +309,39 @@ export const OverlayMixin = (superClass) =>
247
309
 
248
310
  /** @private */
249
311
  _modelessChanged(modeless) {
312
+ if (this.opened) {
313
+ // Add / remove listeners if modeless is changed while opened
314
+ if (this._shouldAddGlobalListeners()) {
315
+ this._addGlobalListeners();
316
+ } else {
317
+ this._removeGlobalListeners();
318
+ }
319
+ }
320
+
250
321
  if (!modeless) {
251
322
  if (this.opened) {
252
- this._addGlobalListeners();
253
323
  this._enterModalState();
254
324
  }
255
325
  } else {
256
- this._removeGlobalListeners();
257
326
  this._exitModalState();
258
327
  }
328
+ setOverlayStateAttribute(this, 'modeless', modeless);
329
+ }
330
+
331
+ /** @private */
332
+ _withBackdropChanged(withBackdrop) {
333
+ setOverlayStateAttribute(this, 'with-backdrop', withBackdrop);
259
334
  }
260
335
 
261
336
  /** @private */
262
337
  _openedChanged(opened, wasOpened) {
263
338
  if (opened) {
339
+ // Prevent possible errors on setting `opened` to `true` while disconnected
340
+ if (!this.isConnected) {
341
+ this.opened = false;
342
+ return;
343
+ }
344
+
264
345
  this._saveFocus();
265
346
 
266
347
  this._animatedOpening();
@@ -269,13 +350,18 @@ export const OverlayMixin = (superClass) =>
269
350
  setTimeout(() => {
270
351
  this._trapFocus();
271
352
 
272
- this.dispatchEvent(new CustomEvent('vaadin-overlay-open', { bubbles: true }));
353
+ // Dispatch the event on the overlay. Not using composed, as propagating the event through shadow roots
354
+ // could have side effects when nesting overlays
355
+ const event = new CustomEvent('vaadin-overlay-open', { detail: { overlay: this }, bubbles: true });
356
+ this.dispatchEvent(event);
357
+ // To allow listening for the event globally, also dispatch it on the document body
358
+ document.body.dispatchEvent(event);
273
359
  });
274
360
  });
275
361
 
276
362
  document.addEventListener('keydown', this._boundKeydownListener);
277
363
 
278
- if (!this.modeless) {
364
+ if (this._shouldAddGlobalListeners()) {
279
365
  this._addGlobalListeners();
280
366
  }
281
367
  } else if (wasOpened) {
@@ -290,7 +376,7 @@ export const OverlayMixin = (superClass) =>
290
376
 
291
377
  document.removeEventListener('keydown', this._boundKeydownListener);
292
378
 
293
- if (!this.modeless) {
379
+ if (this._shouldAddGlobalListeners()) {
294
380
  this._removeGlobalListeners();
295
381
  }
296
382
  }
@@ -346,14 +432,16 @@ export const OverlayMixin = (superClass) =>
346
432
 
347
433
  /** @private */
348
434
  _animatedOpening() {
349
- if (this.parentNode === document.body && this.hasAttribute('closing')) {
435
+ if (this._isAttached && this.hasAttribute('closing')) {
350
436
  this._flushAnimation('closing');
351
437
  }
352
438
  this._attachOverlay();
439
+ this._appendAttachedInstance();
440
+ this.bringToFront();
353
441
  if (!this.modeless) {
354
442
  this._enterModalState();
355
443
  }
356
- this.setAttribute('opening', '');
444
+ setOverlayStateAttribute(this, 'opening', true);
357
445
 
358
446
  if (this._shouldAnimate()) {
359
447
  this._enqueueAnimation('opening', () => {
@@ -366,22 +454,20 @@ export const OverlayMixin = (superClass) =>
366
454
 
367
455
  /** @private */
368
456
  _attachOverlay() {
369
- this._placeholder = document.createComment('vaadin-overlay-placeholder');
370
- this.parentNode.insertBefore(this._placeholder, this);
371
- document.body.appendChild(this);
372
- this.bringToFront();
457
+ this.showPopover();
373
458
  }
374
459
 
375
460
  /** @private */
376
461
  _finishOpening() {
377
- this.removeAttribute('opening');
462
+ setOverlayStateAttribute(this, 'opening', false);
378
463
  }
379
464
 
380
465
  /** @private */
381
466
  _finishClosing() {
382
467
  this._detachOverlay();
468
+ this._removeAttachedInstance();
383
469
  this.$.overlay.style.removeProperty('pointer-events');
384
- this.removeAttribute('closing');
470
+ setOverlayStateAttribute(this, 'closing', false);
385
471
  this.dispatchEvent(new CustomEvent('vaadin-overlay-closed'));
386
472
  }
387
473
 
@@ -390,9 +476,9 @@ export const OverlayMixin = (superClass) =>
390
476
  if (this.hasAttribute('opening')) {
391
477
  this._flushAnimation('opening');
392
478
  }
393
- if (this._placeholder) {
479
+ if (this._isAttached) {
394
480
  this._exitModalState();
395
- this.setAttribute('closing', '');
481
+ setOverlayStateAttribute(this, 'closing', true);
396
482
  this.dispatchEvent(new CustomEvent('vaadin-overlay-closing'));
397
483
 
398
484
  if (this._shouldAnimate()) {
@@ -407,8 +493,7 @@ export const OverlayMixin = (superClass) =>
407
493
 
408
494
  /** @private */
409
495
  _detachOverlay() {
410
- this._placeholder.parentNode.insertBefore(this, this._placeholder);
411
- this._placeholder.parentNode.removeChild(this._placeholder);
496
+ this.hidePopover();
412
497
  }
413
498
 
414
499
  /** @private */
@@ -452,7 +537,6 @@ export const OverlayMixin = (superClass) =>
452
537
  }
453
538
 
454
539
  const evt = new CustomEvent('vaadin-overlay-outside-click', {
455
- bubbles: true,
456
540
  cancelable: true,
457
541
  detail: { sourceEvent: event },
458
542
  });
@@ -473,13 +557,12 @@ export const OverlayMixin = (superClass) =>
473
557
  }
474
558
 
475
559
  // Only close modeless overlay on Esc press when it contains focus
476
- if (this.modeless && !event.composedPath().includes(this.$.overlay)) {
560
+ if (!this._shouldAddGlobalListeners() && !event.composedPath().includes(this._focusTrapRoot)) {
477
561
  return;
478
562
  }
479
563
 
480
564
  if (event.key === 'Escape') {
481
565
  const evt = new CustomEvent('vaadin-overlay-escape-press', {
482
- bubbles: true,
483
566
  cancelable: true,
484
567
  detail: { sourceEvent: event },
485
568
  });
@@ -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',
@@ -116,13 +116,6 @@ export const PositionMixin = (superClass) =>
116
116
  };
117
117
  }
118
118
 
119
- static get observers() {
120
- return [
121
- '__positionSettingsChanged(horizontalAlign, verticalAlign, noHorizontalOverlap, noVerticalOverlap, requiredVerticalSpace)',
122
- '__overlayOpenedChanged(opened, positionTarget)',
123
- ];
124
- }
125
-
126
119
  constructor() {
127
120
  super();
128
121
 
@@ -145,6 +138,36 @@ export const PositionMixin = (superClass) =>
145
138
  this.__removeUpdatePositionEventListeners();
146
139
  }
147
140
 
141
+ /** @protected */
142
+ updated(props) {
143
+ super.updated(props);
144
+
145
+ if (props.has('positionTarget')) {
146
+ const oldTarget = props.get('positionTarget');
147
+
148
+ // 1. When position target is removed, always reset position settings
149
+ // 2. When position target is set, reset if overlay was opened before
150
+ if ((!this.positionTarget && oldTarget) || (this.positionTarget && !oldTarget && !!this.__margins)) {
151
+ this.__resetPosition();
152
+ }
153
+ }
154
+
155
+ if (props.has('opened') || props.has('positionTarget')) {
156
+ this.__updatePositionSettings(this.opened, this.positionTarget);
157
+ }
158
+
159
+ const positionProps = [
160
+ 'horizontalAlign',
161
+ 'verticalAlign',
162
+ 'noHorizontalOverlap',
163
+ 'noVerticalOverlap',
164
+ 'requiredVerticalSpace',
165
+ ];
166
+ if (positionProps.some((prop) => props.has(prop))) {
167
+ this._updatePosition();
168
+ }
169
+ }
170
+
148
171
  /** @private */
149
172
  __addUpdatePositionEventListeners() {
150
173
  window.visualViewport.addEventListener('resize', this._updatePosition);
@@ -181,7 +204,7 @@ export const PositionMixin = (superClass) =>
181
204
  }
182
205
 
183
206
  /** @private */
184
- __overlayOpenedChanged(opened, positionTarget) {
207
+ __updatePositionSettings(opened, positionTarget) {
185
208
  this.__removeUpdatePositionEventListeners();
186
209
 
187
210
  if (positionTarget) {
@@ -210,20 +233,35 @@ export const PositionMixin = (superClass) =>
210
233
  }
211
234
  }
212
235
 
213
- __positionSettingsChanged() {
214
- this._updatePosition();
215
- }
216
-
217
236
  /** @private */
218
237
  __onScroll(e) {
219
238
  // If the scroll event occurred inside the overlay, ignore it.
220
- if (e.target instanceof Node && this.contains(e.target)) {
239
+ if (e.target instanceof Node && this._deepContains(e.target)) {
221
240
  return;
222
241
  }
223
242
 
224
243
  this._updatePosition();
225
244
  }
226
245
 
246
+ /** @private */
247
+ __resetPosition() {
248
+ this.__margins = null;
249
+
250
+ Object.assign(this.style, {
251
+ justifyContent: '',
252
+ alignItems: '',
253
+ top: '',
254
+ bottom: '',
255
+ left: '',
256
+ right: '',
257
+ });
258
+
259
+ setOverlayStateAttribute(this, 'bottom-aligned', false);
260
+ setOverlayStateAttribute(this, 'top-aligned', false);
261
+ setOverlayStateAttribute(this, 'end-aligned', false);
262
+ setOverlayStateAttribute(this, 'start-aligned', false);
263
+ }
264
+
227
265
  _updatePosition() {
228
266
  if (!this.positionTarget || !this.opened || !this.__margins) {
229
267
  return;
@@ -271,11 +309,11 @@ export const PositionMixin = (superClass) =>
271
309
  // Apply the positioning properties to the overlay
272
310
  Object.assign(this.style, verticalProps, horizontalProps);
273
311
 
274
- this.toggleAttribute('bottom-aligned', !shouldAlignStartVertically);
275
- this.toggleAttribute('top-aligned', shouldAlignStartVertically);
312
+ setOverlayStateAttribute(this, 'bottom-aligned', !shouldAlignStartVertically);
313
+ setOverlayStateAttribute(this, 'top-aligned', shouldAlignStartVertically);
276
314
 
277
- this.toggleAttribute('end-aligned', !flexStart);
278
- this.toggleAttribute('start-aligned', flexStart);
315
+ setOverlayStateAttribute(this, 'end-aligned', !flexStart);
316
+ setOverlayStateAttribute(this, 'start-aligned', flexStart);
279
317
  }
280
318
 
281
319
  __shouldAlignStartHorizontally(targetRect, rtl) {
@@ -4,45 +4,43 @@
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
- const getAttachedInstances = () =>
12
- Array.from(document.body.children)
13
- .filter((el) => el instanceof HTMLElement && el._hasOverlayStackMixin && !el.hasAttribute('closing'))
14
- .sort((a, b) => a.__zIndex - b.__zIndex || 0);
14
+ const getAttachedInstances = () => [...attachedInstances].filter((el) => !el.hasAttribute('closing'));
15
15
 
16
16
  /**
17
- * Returns all attached overlay instances excluding notification container,
18
- * which only needs to be in the stack for zIndex but not pointer-events.
17
+ * Returns true if all the instances on top of the overlay are nested overlays.
19
18
  * @private
20
19
  */
21
- const getOverlayInstances = () => getAttachedInstances().filter((el) => el.$.overlay);
20
+ const hasOnlyNestedOverlays = (overlay) => {
21
+ const instances = getAttachedInstances();
22
+ const next = instances[instances.indexOf(overlay) + 1];
23
+ if (!next) {
24
+ return true;
25
+ }
26
+
27
+ if (!overlay._deepContains(next)) {
28
+ return false;
29
+ }
30
+
31
+ return hasOnlyNestedOverlays(next);
32
+ };
22
33
 
23
34
  /**
24
35
  * Returns true if the overlay is the last one in the opened overlays stack.
25
36
  * @param {HTMLElement} overlay
37
+ * @param {function(HTMLElement): boolean} filter
26
38
  * @return {boolean}
27
39
  * @protected
28
40
  */
29
- export const isLastOverlay = (overlay) => overlay === getOverlayInstances().pop();
30
-
31
- const overlayMap = new WeakMap();
32
-
33
- /**
34
- * Stores the reference to the nested overlay for given parent,
35
- * or removes it when the nested overlay is null.
36
- * @param {HTMLElement} parent
37
- * @param {HTMLElement} nested
38
- * @protected
39
- */
40
- export const setNestedOverlay = (parent, nested) => {
41
- if (nested != null) {
42
- overlayMap.set(parent, nested);
43
- } else {
44
- overlayMap.delete(parent);
45
- }
41
+ export const isLastOverlay = (overlay, filter = (_overlay) => true) => {
42
+ const filteredOverlays = getAttachedInstances().filter(filter);
43
+ return overlay === filteredOverlays.pop();
46
44
  };
47
45
 
48
46
  /**
@@ -50,12 +48,6 @@ export const setNestedOverlay = (parent, nested) => {
50
48
  */
51
49
  export const OverlayStackMixin = (superClass) =>
52
50
  class OverlayStackMixin extends superClass {
53
- constructor() {
54
- super();
55
-
56
- this._hasOverlayStackMixin = true;
57
- }
58
-
59
51
  /**
60
52
  * Returns true if this is the last one in the opened overlays stack.
61
53
  *
@@ -66,25 +58,36 @@ export const OverlayStackMixin = (superClass) =>
66
58
  return isLastOverlay(this);
67
59
  }
68
60
 
61
+ /**
62
+ * Returns true if this is overlay is attached.
63
+ *
64
+ * @return {boolean}
65
+ * @protected
66
+ */
67
+ get _isAttached() {
68
+ return attachedInstances.has(this);
69
+ }
70
+
69
71
  /**
70
72
  * Brings the overlay as visually the frontmost one.
71
73
  */
72
74
  bringToFront() {
73
- let zIndex = '';
74
- const frontmost = getAttachedInstances()
75
- .filter((o) => o !== this)
76
- .pop();
77
- if (frontmost) {
78
- const frontmostZIndex = frontmost.__zIndex;
79
- zIndex = frontmostZIndex + 1;
75
+ // If the overlay is the last one, or if all other overlays shown above
76
+ // are nested overlays (e.g. date-picker inside a dialog), do not call
77
+ // `showPopover()` unnecessarily to avoid scroll position being reset.
78
+ if (isLastOverlay(this) || hasOnlyNestedOverlays(this)) {
79
+ return;
80
80
  }
81
- this.style.zIndex = zIndex;
82
- this.__zIndex = zIndex || parseFloat(getComputedStyle(this).zIndex);
83
81
 
84
- // If there is a nested overlay, call `bringToFront()` for it as well.
85
- if (overlayMap.has(this)) {
86
- overlayMap.get(this).bringToFront();
82
+ // Update stacking order of native popover-based overlays
83
+ if (this.matches(':popover-open')) {
84
+ this.hidePopover();
85
+ this.showPopover();
87
86
  }
87
+
88
+ // Update order of attached instances
89
+ this._removeAttachedInstance();
90
+ this._appendAttachedInstance();
88
91
  }
89
92
 
90
93
  /** @protected */
@@ -97,7 +100,7 @@ export const OverlayStackMixin = (superClass) =>
97
100
  }
98
101
 
99
102
  // Disable pointer events in other attached overlays
100
- getOverlayInstances().forEach((el) => {
103
+ getAttachedInstances().forEach((el) => {
101
104
  if (el !== this) {
102
105
  el.$.overlay.style.pointerEvents = 'none';
103
106
  }
@@ -113,7 +116,7 @@ export const OverlayStackMixin = (superClass) =>
113
116
  }
114
117
 
115
118
  // Restore pointer events in the previous overlay(s)
116
- const instances = getOverlayInstances();
119
+ const instances = getAttachedInstances();
117
120
 
118
121
  let el;
119
122
  // Use instances.pop() to ensure the reverse order
@@ -129,4 +132,16 @@ export const OverlayStackMixin = (superClass) =>
129
132
  }
130
133
  }
131
134
  }
135
+
136
+ /** @protected */
137
+ _appendAttachedInstance() {
138
+ attachedInstances.add(this);
139
+ }
140
+
141
+ /** @protected */
142
+ _removeAttachedInstance() {
143
+ if (this._isAttached) {
144
+ attachedInstances.delete(this);
145
+ }
146
+ }
132
147
  };
@@ -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;
@@ -16,10 +16,12 @@
16
16
  */
17
17
  export function observeMove(element, callback) {
18
18
  let io = null;
19
+ let timeout;
19
20
 
20
21
  const root = document.documentElement;
21
22
 
22
23
  function cleanup() {
24
+ timeout && clearTimeout(timeout);
23
25
  io && io.disconnect();
24
26
  io = null;
25
27
  }
@@ -52,27 +54,22 @@ export function observeMove(element, callback) {
52
54
  let isFirstUpdate = true;
53
55
 
54
56
  function handleObserve(entries) {
55
- let ratio = entries[0].intersectionRatio;
57
+ const ratio = entries[0].intersectionRatio;
56
58
 
57
59
  if (ratio !== threshold) {
58
60
  if (!isFirstUpdate) {
59
61
  return refresh();
60
62
  }
61
63
 
62
- // It's possible for the watched element to not be at perfect 1.0 visibility when we create
63
- // the IntersectionObserver. This has a couple of causes:
64
- // - elements being on partial pixels
65
- // - elements being hidden offscreen (e.g., <html> has `overflow: hidden`)
66
- // - delays: if your DOM change occurs due to e.g., page resize, you can see elements
67
- // behind their actual position
68
- //
69
- // In all of these cases, refresh but with this lower ratio of threshold. When the element
70
- // moves beneath _that_ new value, the user will get notified.
71
- if (ratio === 0.0) {
72
- ratio = 0.0000001; // Just needs to be non-zero
64
+ if (!ratio) {
65
+ // If the reference is clipped, the ratio is 0. Throttle the refresh
66
+ // to prevent an infinite loop of updates.
67
+ timeout = setTimeout(() => {
68
+ refresh(false, 1e-7);
69
+ }, 1000);
70
+ } else {
71
+ refresh(false, ratio);
73
72
  }
74
-
75
- refresh(false, ratio);
76
73
  }
77
74
 
78
75
  isFirstUpdate = false;
@@ -87,3 +84,32 @@ export function observeMove(element, callback) {
87
84
 
88
85
  return cleanup;
89
86
  }
87
+
88
+ /**
89
+ * Toggle the state attribute on the overlay element and also its owner element. This allows targeting state attributes
90
+ * in the light DOM in case the overlay is in the shadow DOM of its owner.
91
+ * @param {HTMLElement} overlay The overlay element on which to toggle the attribute.
92
+ * @param {string} name The name of the attribute to toggle.
93
+ * @param {string|boolean} value The value of the attribute. If a string is provided, it will be set as the attribute
94
+ * value. Otherwise, the attribute will be added or removed depending on whether `value` is truthy or falsy.
95
+ */
96
+ export function setOverlayStateAttribute(overlay, name, value) {
97
+ const elements = [overlay];
98
+ if (overlay.owner) {
99
+ elements.push(overlay.owner);
100
+ }
101
+
102
+ if (typeof value === 'string') {
103
+ elements.forEach((element) => {
104
+ element.setAttribute(name, value);
105
+ });
106
+ } else if (value) {
107
+ elements.forEach((element) => {
108
+ element.setAttribute(name, '');
109
+ });
110
+ } else {
111
+ elements.forEach((element) => {
112
+ element.removeAttribute(name);
113
+ });
114
+ }
115
+ }
@@ -17,13 +17,13 @@ export type OverlayOpenedChangedEvent = CustomEvent<{ value: boolean }>;
17
17
  /**
18
18
  * Fired after the overlay is opened.
19
19
  */
20
- export type OverlayOpenEvent = CustomEvent;
20
+ export type OverlayOpenEvent = CustomEvent<{ overlay: HTMLElement }>;
21
21
 
22
22
  /**
23
23
  * Fired when the opened overlay is about to be closed.
24
24
  * Calling `preventDefault()` on the event cancels the closing.
25
25
  */
26
- export type OverlayCloseEvent = CustomEvent;
26
+ export type OverlayCloseEvent = CustomEvent<{ overlay: HTMLElement }>;
27
27
 
28
28
  /**
29
29
  * Fired after the overlay is closed.
@@ -98,10 +98,10 @@ export type OverlayEventMap = HTMLElementEventMap & OverlayCustomEventMap;
98
98
  *
99
99
  * The following state attributes are available for styling:
100
100
  *
101
- * Attribute | Description | Part
102
- * ---|---|---
103
- * `opening` | Applied just after the overlay is attached to the DOM. You can apply a CSS @keyframe animation for this state. | `:host`
104
- * `closing` | Applied just before the overlay is detached from the DOM. You can apply a CSS @keyframe animation for this state. | `:host`
101
+ * Attribute | Description
102
+ * ----------|------------
103
+ * `opening` | Applied just after the overlay is opened. You can apply a CSS animation for this state.
104
+ * `closing` | Applied just before the overlay is closed. You can apply a CSS animation for this state.
105
105
  *
106
106
  * The following custom CSS properties are available for styling:
107
107
  *
@@ -7,9 +7,10 @@ import { html, LitElement } from 'lit';
7
7
  import { defineCustomElement } from '@vaadin/component-base/src/define.js';
8
8
  import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
9
9
  import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
10
+ import { LumoInjectionMixin } from '@vaadin/vaadin-themable-mixin/lumo-injection-mixin.js';
10
11
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
12
+ import { overlayStyles } from './styles/vaadin-overlay-base-styles.js';
11
13
  import { OverlayMixin } from './vaadin-overlay-mixin.js';
12
- import { overlayStyles } from './vaadin-overlay-styles.js';
13
14
 
14
15
  /**
15
16
  * `<vaadin-overlay>` is a Web Component for creating overlays. The content of the overlay
@@ -49,10 +50,10 @@ import { overlayStyles } from './vaadin-overlay-styles.js';
49
50
  *
50
51
  * The following state attributes are available for styling:
51
52
  *
52
- * Attribute | Description | Part
53
- * ---|---|---
54
- * `opening` | Applied just after the overlay is attached to the DOM. You can apply a CSS @keyframe animation for this state. | `:host`
55
- * `closing` | Applied just before the overlay is detached from the DOM. You can apply a CSS @keyframe animation for this state. | `:host`
53
+ * Attribute | Description
54
+ * ----------|------------
55
+ * `opening` | Applied just after the overlay is opened. You can apply a CSS animation for this state.
56
+ * `closing` | Applied just before the overlay is closed. You can apply a CSS animation for this state.
56
57
  *
57
58
  * The following custom CSS properties are available for styling:
58
59
  *
@@ -76,7 +77,7 @@ import { overlayStyles } from './vaadin-overlay-styles.js';
76
77
  * @mixes DirMixin
77
78
  * @mixes OverlayMixin
78
79
  */
79
- class Overlay extends OverlayMixin(DirMixin(ThemableMixin(PolylitMixin(LitElement)))) {
80
+ class Overlay extends OverlayMixin(DirMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
80
81
  static get is() {
81
82
  return 'vaadin-overlay';
82
83
  }
package/vaadin-overlay.js CHANGED
@@ -1,2 +1,2 @@
1
- import './theme/lumo/vaadin-overlay.js';
1
+ import './src/vaadin-overlay.js';
2
2
  export * from './src/vaadin-overlay.js';
@@ -1,82 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright (c) 2017 - 2025 Vaadin Ltd.
4
- * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
- */
6
- import '@vaadin/component-base/src/style-props.js';
7
- import { css } from 'lit';
8
-
9
- export const overlayStyles = css`
10
- @layer base {
11
- :host {
12
- z-index: 200;
13
- position: fixed;
14
-
15
- /* Despite of what the names say, <vaadin-overlay> is just a container
16
- for position/sizing/alignment. The actual overlay is the overlay part. */
17
-
18
- /* Default position constraints. Themes can
19
- override this to adjust the gap between the overlay and the viewport. */
20
- inset: 8px;
21
- bottom: var(--vaadin-overlay-viewport-bottom);
22
-
23
- /* Use flexbox alignment for the overlay part. */
24
- display: flex;
25
- flex-direction: column; /* makes dropdowns sizing easier */
26
- /* Align to center by default. */
27
- align-items: center;
28
- justify-content: center;
29
-
30
- /* Allow centering when max-width/max-height applies. */
31
- margin: auto;
32
-
33
- /* The host is not clickable, only the overlay part is. */
34
- pointer-events: none;
35
-
36
- /* Remove tap highlight on touch devices. */
37
- -webkit-tap-highlight-color: transparent;
38
-
39
- /* CSS API for host */
40
- --vaadin-overlay-viewport-bottom: 8px;
41
- }
42
-
43
- :host([hidden]),
44
- :host(:not([opened]):not([closing])),
45
- :host(:not([opened]):not([closing])) [part='overlay'] {
46
- display: none !important;
47
- }
48
-
49
- [part='overlay'] {
50
- background: var(--vaadin-overlay-background, var(--_vaadin-background));
51
- border: var(--vaadin-overlay-border, 1px solid var(--_vaadin-border-color));
52
- border-radius: var(--vaadin-overlay-border-radius, var(--_vaadin-radius-m));
53
- box-shadow: var(--vaadin-overlay-box-shadow, 0 8px 24px -4px hsl(0 0 0 / 0.3));
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
- }
61
-
62
- [part='backdrop'] {
63
- background: var(--vaadin-overlay-backdrop-background, rgba(0, 0, 0, 0.5));
64
- content: '';
65
- inset: 0;
66
- pointer-events: auto;
67
- position: fixed;
68
- z-index: -1;
69
- }
70
-
71
- @media (forced-colors: active) {
72
- [part='overlay'] {
73
- border: 3px solid;
74
- }
75
-
76
- [part='overlay']:focus-visible {
77
- outline: var(--vaadin-focus-ring-width) solid;
78
- outline-offset: 1px;
79
- }
80
- }
81
- }
82
- `;
@@ -1,67 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright (c) 2017 - 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
-
8
- export const overlayStyles = css`
9
- :host {
10
- z-index: 200;
11
- position: fixed;
12
-
13
- /* Despite of what the names say, <vaadin-overlay> is just a container
14
- for position/sizing/alignment. The actual overlay is the overlay part. */
15
-
16
- /* Default position constraints: the entire viewport. Note: themes can
17
- override this to introduce gaps between the overlay and the viewport. */
18
- inset: 0;
19
- bottom: var(--vaadin-overlay-viewport-bottom);
20
-
21
- /* Use flexbox alignment for the overlay part. */
22
- display: flex;
23
- flex-direction: column; /* makes dropdowns sizing easier */
24
- /* Align to center by default. */
25
- align-items: center;
26
- justify-content: center;
27
-
28
- /* Allow centering when max-width/max-height applies. */
29
- margin: auto;
30
-
31
- /* The host is not clickable, only the overlay part is. */
32
- pointer-events: none;
33
-
34
- /* Remove tap highlight on touch devices. */
35
- -webkit-tap-highlight-color: transparent;
36
-
37
- /* CSS API for host */
38
- --vaadin-overlay-viewport-bottom: 0;
39
- }
40
-
41
- :host([hidden]),
42
- :host(:not([opened]):not([closing])),
43
- :host(:not([opened]):not([closing])) [part='overlay'] {
44
- display: none !important;
45
- }
46
-
47
- [part='overlay'] {
48
- -webkit-overflow-scrolling: touch;
49
- overflow: auto;
50
- pointer-events: auto;
51
-
52
- /* Prevent overflowing the host */
53
- max-width: 100%;
54
- box-sizing: border-box;
55
-
56
- -webkit-tap-highlight-color: initial; /* reenable tap highlight inside */
57
- }
58
-
59
- [part='backdrop'] {
60
- z-index: -1;
61
- content: '';
62
- background: rgba(0, 0, 0, 0.5);
63
- position: fixed;
64
- inset: 0;
65
- pointer-events: auto;
66
- }
67
- `;
@@ -1,6 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright (c) 2017 - 2025 Vaadin Ltd.
4
- * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
- */
6
- export { overlayStyles } from './vaadin-overlay-core-styles.js';
@@ -1 +0,0 @@
1
- export {};
@@ -1,4 +0,0 @@
1
- import { overlay } from '@vaadin/vaadin-lumo-styles/mixins/overlay.js';
2
- import { registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
3
-
4
- registerStyles('vaadin-overlay', overlay, { moduleId: 'lumo-vaadin-overlay' });
@@ -1,2 +0,0 @@
1
- import './vaadin-overlay-styles.js';
2
- import '../../src/vaadin-overlay.js';
@@ -1,2 +0,0 @@
1
- import './vaadin-overlay-styles.js';
2
- import '../../src/vaadin-overlay.js';