@vaadin/overlay 25.3.0-alpha9 → 25.3.0-beta1

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.
@@ -639,7 +639,7 @@
639
639
  },
640
640
  {
641
641
  "kind": "function",
642
- "name": "shouldAnimate",
642
+ "name": "getStateAnimations",
643
643
  "parameters": [
644
644
  {
645
645
  "name": "element",
@@ -648,10 +648,10 @@
648
648
  }
649
649
  }
650
650
  ],
651
- "description": "Detect whether an animation runs on the given element, so that its end can be\nawaited before the element is hidden or removed. An element that is not rendered,\nhas no animation name, or has a zero duration does not fire `animationend`.",
651
+ "description": "Collect the animations that report the state of the given element, so that their end can be\nawaited before the element is hidden or removed. The animations are read instead of the\ncomputed style, so that the decision to wait cannot disagree with what the browser actually\ncreated: a keyframes rule that does not exist and an element that is not rendered both give\nan empty list.\n\nOnly CSS animations count, as the transitions and the script animations that `getAnimations()`\nalso returns do not report the state. Animations of any content are already left out, as\n`getAnimations()` only descends into the subtree when asked to. Animations that take no time\nare dropped as well, so that a delay on its own does not hold the state.",
652
652
  "return": {
653
653
  "type": {
654
- "text": "boolean"
654
+ "text": "!Array<!Animation>"
655
655
  }
656
656
  }
657
657
  },
@@ -695,9 +695,9 @@
695
695
  },
696
696
  {
697
697
  "kind": "js",
698
- "name": "shouldAnimate",
698
+ "name": "getStateAnimations",
699
699
  "declaration": {
700
- "name": "shouldAnimate",
700
+ "name": "getStateAnimations",
701
701
  "module": "src/vaadin-overlay-utils.js"
702
702
  }
703
703
  },
@@ -1020,6 +1020,7 @@
1020
1020
  },
1021
1021
  "tagName": "vaadin-overlay",
1022
1022
  "customElement": true,
1023
+ "deprecated": "`<vaadin-overlay>` is deprecated and will be removed in Vaadin 26. Consider using `OverlayMixin` and `PositionMixin` instead.",
1023
1024
  "attributes": [
1024
1025
  {
1025
1026
  "name": "autofocus",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/overlay",
3
- "version": "25.3.0-alpha9",
3
+ "version": "25.3.0-beta1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -34,19 +34,19 @@
34
34
  ],
35
35
  "dependencies": {
36
36
  "@open-wc/dedupe-mixin": "^1.3.0",
37
- "@vaadin/a11y-base": "25.3.0-alpha9",
38
- "@vaadin/component-base": "25.3.0-alpha9",
39
- "@vaadin/vaadin-themable-mixin": "25.3.0-alpha9",
37
+ "@vaadin/a11y-base": "25.3.0-beta1",
38
+ "@vaadin/component-base": "25.3.0-beta1",
39
+ "@vaadin/vaadin-themable-mixin": "25.3.0-beta1",
40
40
  "lit": "^3.0.0"
41
41
  },
42
42
  "devDependencies": {
43
- "@vaadin/aura": "25.3.0-alpha9",
44
- "@vaadin/chai-plugins": "25.3.0-alpha9",
45
- "@vaadin/test-runner-commands": "25.3.0-alpha9",
43
+ "@vaadin/aura": "25.3.0-beta1",
44
+ "@vaadin/chai-plugins": "25.3.0-beta1",
45
+ "@vaadin/test-runner-commands": "25.3.0-beta1",
46
46
  "@vaadin/testing-helpers": "^2.0.0",
47
- "@vaadin/vaadin-lumo-styles": "25.3.0-alpha9",
47
+ "@vaadin/vaadin-lumo-styles": "25.3.0-beta1",
48
48
  "sinon": "^22.0.0"
49
49
  },
50
50
  "customElements": "custom-elements.json",
51
- "gitHead": "cb915ebde095ec5b94a87af93dd4530f51984c52"
51
+ "gitHead": "295432e44a6967e1aff36462b2e3e1d0e64eb8cc"
52
52
  }
@@ -56,6 +56,11 @@ const overlayBase = css`
56
56
  display: none !important;
57
57
  }
58
58
 
59
+ :host([suppressed]) [part='overlay'],
60
+ :host([suppressed]) ::slotted(*) {
61
+ pointer-events: none !important;
62
+ }
63
+
59
64
  [part='overlay'] {
60
65
  color: var(--vaadin-overlay-text-color, var(--vaadin-text-color));
61
66
  background: var(--vaadin-overlay-background, var(--vaadin-background-color));
@@ -6,7 +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, shouldAnimate } from './vaadin-overlay-utils.js';
9
+ import { getStateAnimations, setOverlayStateAttribute } from './vaadin-overlay-utils.js';
10
10
 
11
11
  export const OverlayMixin = (superClass) =>
12
12
  class OverlayMixin extends OverlayFocusMixin(OverlayStackMixin(superClass)) {
@@ -132,11 +132,6 @@ export const OverlayMixin = (superClass) =>
132
132
  if (this.$.backdrop) {
133
133
  this.$.backdrop.addEventListener('click', () => {});
134
134
  }
135
-
136
- this.addEventListener('animationcancel', () => {
137
- this._flushAnimation('opening');
138
- this._flushAnimation('closing');
139
- });
140
135
  }
141
136
 
142
137
  /** @protected */
@@ -393,30 +388,35 @@ export const OverlayMixin = (superClass) =>
393
388
  }
394
389
 
395
390
  /**
396
- * @return {boolean}
397
- * @private
398
- */
399
- _shouldAnimate() {
400
- return shouldAnimate(this);
401
- }
402
-
403
- /**
391
+ * Run the callback once every animation reporting the state has ended, or right away when
392
+ * there is none.
393
+ *
404
394
  * @param {string} type
405
395
  * @param {Function} callback
406
396
  * @private
407
397
  */
408
398
  _enqueueAnimation(type, callback) {
399
+ const animations = getStateAnimations(this);
400
+ if (animations.length === 0) {
401
+ callback();
402
+ return;
403
+ }
404
+
409
405
  const handler = `__${type}Handler`;
410
- const listener = (event) => {
411
- if (event && event.target !== this) {
406
+ const finish = () => {
407
+ // The phase may already have been finished by _flushAnimation(), or superseded by a
408
+ // later one of the same type, in which case this callback no longer applies
409
+ if (this[handler] !== finish) {
412
410
  return;
413
411
  }
414
- callback();
415
- this.removeEventListener('animationend', listener);
412
+ // Cleared before the callback, so that a listener reopening the overlay synchronously
413
+ // installs its own handler rather than having it deleted afterwards
416
414
  delete this[handler];
415
+ callback();
417
416
  };
418
- this[handler] = listener;
419
- this.addEventListener('animationend', listener);
417
+ this[handler] = finish;
418
+ // A cancelled animation rejects, which ends the phase just as finishing does
419
+ Promise.all(animations.map((animation) => animation.finished)).then(finish, finish);
420
420
  }
421
421
 
422
422
  /**
@@ -437,19 +437,14 @@ export const OverlayMixin = (superClass) =>
437
437
  }
438
438
  this._attachOverlay();
439
439
  this._appendAttachedInstance();
440
- this.bringToFront();
441
440
  if (!this.modeless) {
442
441
  this._enterModalState();
443
442
  }
444
443
  setOverlayStateAttribute(this, 'opening', true);
445
444
 
446
- if (this._shouldAnimate()) {
447
- this._enqueueAnimation('opening', () => {
448
- this._finishOpening();
449
- });
450
- } else {
445
+ this._enqueueAnimation('opening', () => {
451
446
  this._finishOpening();
452
- }
447
+ });
453
448
  }
454
449
 
455
450
  /** @private */
@@ -468,7 +463,7 @@ export const OverlayMixin = (superClass) =>
468
463
  _finishClosing() {
469
464
  this._detachOverlay();
470
465
  this._removeAttachedInstance();
471
- this.$.overlay.style.removeProperty('pointer-events');
466
+ this.toggleAttribute('suppressed', false);
472
467
  setOverlayStateAttribute(this, 'closing', false);
473
468
  this.dispatchEvent(new CustomEvent('vaadin-overlay-closed'));
474
469
  }
@@ -483,13 +478,9 @@ export const OverlayMixin = (superClass) =>
483
478
  setOverlayStateAttribute(this, 'closing', true);
484
479
  this.dispatchEvent(new CustomEvent('vaadin-overlay-closing'));
485
480
 
486
- if (this._shouldAnimate()) {
487
- this._enqueueAnimation('closing', () => {
488
- this._finishClosing();
489
- });
490
- } else {
481
+ this._enqueueAnimation('closing', () => {
491
482
  this._finishClosing();
492
- }
483
+ });
493
484
  }
494
485
  }
495
486
 
@@ -546,6 +537,11 @@ export const OverlayMixin = (superClass) =>
546
537
 
547
538
  if (this.opened && !evt.defaultPrevented) {
548
539
  this.close(event);
540
+
541
+ // Only for modal overlays which make underlying content non-interactive.
542
+ if (!this.opened && !this.modeless) {
543
+ event.preventDefault();
544
+ }
549
545
  }
550
546
  }
551
547
 
@@ -106,10 +106,10 @@ export const OverlayStackMixin = (superClass) =>
106
106
  document.body.style.pointerEvents = 'none';
107
107
  }
108
108
 
109
- // Disable pointer events in other attached overlays
109
+ // Suppress pointer events in other attached overlays
110
110
  getAttachedInstances().forEach((el) => {
111
111
  if (el !== this) {
112
- el.$.overlay.style.pointerEvents = 'none';
112
+ el.toggleAttribute('suppressed', true);
113
113
  }
114
114
  });
115
115
  }
@@ -122,7 +122,7 @@ export const OverlayStackMixin = (superClass) =>
122
122
  delete this._previousDocumentPointerEvents;
123
123
  }
124
124
 
125
- // Restore pointer events in the previous overlay(s)
125
+ // Stop suppressing pointer events in the previous overlay(s)
126
126
  const instances = getAttachedInstances();
127
127
 
128
128
  let el;
@@ -132,7 +132,7 @@ export const OverlayStackMixin = (superClass) =>
132
132
  // Skip the current instance
133
133
  continue;
134
134
  }
135
- el.$.overlay.style.removeProperty('pointer-events');
135
+ el.toggleAttribute('suppressed', false);
136
136
  if (!el.modeless) {
137
137
  // Stop after the last modal
138
138
  break;
@@ -13,11 +13,18 @@
13
13
  export function observeMove(element: HTMLElement, callback: () => void): () => void;
14
14
 
15
15
  /**
16
- * Detect whether an animation runs on the given element, so that its end can be
17
- * awaited before the element is hidden or removed. An element that is not rendered,
18
- * has no animation name, or has a zero duration does not fire `animationend`.
16
+ * Collect the animations that report the state of the given element, so that their end can be
17
+ * awaited before the element is hidden or removed. The animations are read instead of the
18
+ * computed style, so that the decision to wait cannot disagree with what the browser actually
19
+ * created: a keyframes rule that does not exist and an element that is not rendered both give
20
+ * an empty list.
21
+ *
22
+ * Only CSS animations count, as the transitions and the script animations that `getAnimations()`
23
+ * also returns do not report the state. Animations of any content are already left out, as
24
+ * `getAnimations()` only descends into the subtree when asked to. Animations that take no time
25
+ * are dropped as well, so that a delay on its own does not hold the state.
19
26
  */
20
- export function shouldAnimate(element: HTMLElement): boolean;
27
+ export function getStateAnimations(element: HTMLElement): Animation[];
21
28
 
22
29
  /**
23
30
  * Toggle the state attribute on the overlay element and also its owner element. This allows targeting state attributes
@@ -86,21 +86,26 @@ export function observeMove(element, callback) {
86
86
  }
87
87
 
88
88
  /**
89
- * Detect whether an animation runs on the given element, so that its end can be
90
- * awaited before the element is hidden or removed. An element that is not rendered,
91
- * has no animation name, or has a zero duration does not fire `animationend`.
89
+ * Collect the animations that report the state of the given element, so that their end can be
90
+ * awaited before the element is hidden or removed. The animations are read instead of the
91
+ * computed style, so that the decision to wait cannot disagree with what the browser actually
92
+ * created: a keyframes rule that does not exist and an element that is not rendered both give
93
+ * an empty list.
94
+ *
95
+ * Only CSS animations count, as the transitions and the script animations that `getAnimations()`
96
+ * also returns do not report the state. Animations of any content are already left out, as
97
+ * `getAnimations()` only descends into the subtree when asked to. Animations that take no time
98
+ * are dropped as well, so that a delay on its own does not hold the state.
92
99
  *
93
100
  * @param {HTMLElement} element
94
- * @return {boolean}
101
+ * @return {!Array<!Animation>}
95
102
  */
96
- export function shouldAnimate(element) {
97
- const style = getComputedStyle(element);
98
- const name = style.getPropertyValue('animation-name');
99
- const hasDuration = style
100
- .getPropertyValue('animation-duration')
101
- .split(',')
102
- .some((duration) => parseFloat(duration) > 0);
103
- return style.getPropertyValue('display') !== 'none' && name && name !== 'none' && hasDuration;
103
+ export function getStateAnimations(element) {
104
+ return element
105
+ .getAnimations()
106
+ .filter(
107
+ (animation) => animation instanceof CSSAnimation && animation.effect.getComputedTiming().activeDuration > 0,
108
+ );
104
109
  }
105
110
 
106
111
  /**
@@ -118,6 +118,8 @@ export type OverlayEventMap = HTMLElementEventMap & OverlayCustomEventMap;
118
118
  * @fires {CustomEvent} vaadin-overlay-closed - Fired after the overlay is closed.
119
119
  * @fires {CustomEvent} vaadin-overlay-outside-click - Fired before the overlay is closed on outside click. Calling `preventDefault()` on the event cancels the closing.
120
120
  * @fires {CustomEvent} vaadin-overlay-escape-press - Fired before the overlay is closed on Escape key press. Calling `preventDefault()` on the event cancels the closing.
121
+ * @deprecated `<vaadin-overlay>` is deprecated and will be removed in Vaadin 26.
122
+ * Consider using `OverlayMixin` and `PositionMixin` instead.
121
123
  */
122
124
  declare class Overlay extends OverlayMixin(ThemableMixin(DirMixin(HTMLElement))) {
123
125
  addEventListener<K extends keyof OverlayEventMap>(
@@ -7,6 +7,7 @@ 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 { issueWarning } from '@vaadin/component-base/src/warnings.js';
10
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';
12
13
  import { overlayStyles } from './styles/vaadin-overlay-base-styles.js';
@@ -73,6 +74,8 @@ import { OverlayMixin } from './vaadin-overlay-mixin.js';
73
74
  *
74
75
  * @customElement vaadin-overlay
75
76
  * @extends HTMLElement
77
+ * @deprecated `<vaadin-overlay>` is deprecated and will be removed in Vaadin 26.
78
+ * Consider using `OverlayMixin` and `PositionMixin` instead.
76
79
  */
77
80
  class Overlay extends OverlayMixin(DirMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
78
81
  static get is() {
@@ -94,6 +97,15 @@ class Overlay extends OverlayMixin(DirMixin(ThemableMixin(PolylitMixin(LumoInjec
94
97
  </div>
95
98
  `;
96
99
  }
100
+
101
+ /** @protected */
102
+ firstUpdated() {
103
+ super.firstUpdated();
104
+
105
+ issueWarning(
106
+ '`<vaadin-overlay>` is deprecated and will be removed in Vaadin 26. Consider using `OverlayMixin` and `PositionMixin` instead.',
107
+ );
108
+ }
97
109
  }
98
110
 
99
111
  defineCustomElement(Overlay);