@vaadin/overlay 25.3.0-alpha7 → 25.3.0-alpha9

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.
@@ -26,6 +26,16 @@
26
26
  "description": "",
27
27
  "name": "OverlayFocusMixin",
28
28
  "members": [
29
+ {
30
+ "kind": "field",
31
+ "name": "autofocus",
32
+ "privacy": "public",
33
+ "type": {
34
+ "text": "boolean"
35
+ },
36
+ "description": "Set to true to move focus into the overlay automatically on open.\n\nFocus moves to the first tabbable element in the tab order. This\ncan be the overlay itself if it has `tabindex` attribute set to `0`\non the host element or the `overlay` shadow DOM part.",
37
+ "attribute": "autofocus"
38
+ },
29
39
  {
30
40
  "kind": "field",
31
41
  "name": "focusTrap",
@@ -33,7 +43,7 @@
33
43
  "type": {
34
44
  "text": "boolean"
35
45
  },
36
- "description": "When true, opening the overlay moves focus to the first focusable child,\nor to the overlay part with tabindex if there are no focusable children.",
46
+ "description": "Set to true to move focus into the overlay automatically on open\nand keep it inside: Tab and Shift+Tab cycle through the overlay's\ncontent until the overlay is closed.\n\nFocus moves to the first tabbable element in the tab order. This\ncan be the overlay itself if it has `tabindex` attribute set to `0`\non the host element or the `overlay` shadow DOM part.",
37
47
  "attribute": "focus-trap"
38
48
  },
39
49
  {
@@ -58,12 +68,20 @@
58
68
  }
59
69
  ],
60
70
  "attributes": [
71
+ {
72
+ "name": "autofocus",
73
+ "type": {
74
+ "text": "boolean"
75
+ },
76
+ "description": "Set to true to move focus into the overlay automatically on open.\n\nFocus moves to the first tabbable element in the tab order. This\ncan be the overlay itself if it has `tabindex` attribute set to `0`\non the host element or the `overlay` shadow DOM part.",
77
+ "fieldName": "autofocus"
78
+ },
61
79
  {
62
80
  "name": "focus-trap",
63
81
  "type": {
64
82
  "text": "boolean"
65
83
  },
66
- "description": "When true, opening the overlay moves focus to the first focusable child,\nor to the overlay part with tabindex if there are no focusable children.",
84
+ "description": "Set to true to move focus into the overlay automatically on open\nand keep it inside: Tab and Shift+Tab cycle through the overlay's\ncontent until the overlay is closed.\n\nFocus moves to the first tabbable element in the tab order. This\ncan be the overlay itself if it has `tabindex` attribute set to `0`\non the host element or the `overlay` shadow DOM part.",
67
85
  "fieldName": "focusTrap"
68
86
  },
69
87
  {
@@ -110,6 +128,20 @@
110
128
  "description": "",
111
129
  "name": "OverlayMixin",
112
130
  "members": [
131
+ {
132
+ "kind": "field",
133
+ "name": "autofocus",
134
+ "privacy": "public",
135
+ "type": {
136
+ "text": "boolean"
137
+ },
138
+ "description": "Set to true to move focus into the overlay automatically on open.\n\nFocus moves to the first tabbable element in the tab order. This\ncan be the overlay itself if it has `tabindex` attribute set to `0`\non the host element or the `overlay` shadow DOM part.",
139
+ "attribute": "autofocus",
140
+ "inheritedFrom": {
141
+ "name": "OverlayFocusMixin",
142
+ "module": "src/vaadin-overlay-focus-mixin.js"
143
+ }
144
+ },
113
145
  {
114
146
  "kind": "method",
115
147
  "name": "bringToFront",
@@ -138,7 +170,7 @@
138
170
  "type": {
139
171
  "text": "boolean"
140
172
  },
141
- "description": "When true, opening the overlay moves focus to the first focusable child,\nor to the overlay part with tabindex if there are no focusable children.",
173
+ "description": "Set to true to move focus into the overlay automatically on open\nand keep it inside: Tab and Shift+Tab cycle through the overlay's\ncontent until the overlay is closed.\n\nFocus moves to the first tabbable element in the tab order. This\ncan be the overlay itself if it has `tabindex` attribute set to `0`\non the host element or the `overlay` shadow DOM part.",
142
174
  "attribute": "focus-trap",
143
175
  "inheritedFrom": {
144
176
  "name": "OverlayFocusMixin",
@@ -284,12 +316,24 @@
284
316
  }
285
317
  ],
286
318
  "attributes": [
319
+ {
320
+ "name": "autofocus",
321
+ "type": {
322
+ "text": "boolean"
323
+ },
324
+ "description": "Set to true to move focus into the overlay automatically on open.\n\nFocus moves to the first tabbable element in the tab order. This\ncan be the overlay itself if it has `tabindex` attribute set to `0`\non the host element or the `overlay` shadow DOM part.",
325
+ "fieldName": "autofocus",
326
+ "inheritedFrom": {
327
+ "name": "OverlayFocusMixin",
328
+ "module": "src/vaadin-overlay-focus-mixin.js"
329
+ }
330
+ },
287
331
  {
288
332
  "name": "focus-trap",
289
333
  "type": {
290
334
  "text": "boolean"
291
335
  },
292
- "description": "When true, opening the overlay moves focus to the first focusable child,\nor to the overlay part with tabindex if there are no focusable children.",
336
+ "description": "Set to true to move focus into the overlay automatically on open\nand keep it inside: Tab and Shift+Tab cycle through the overlay's\ncontent until the overlay is closed.\n\nFocus moves to the first tabbable element in the tab order. This\ncan be the overlay itself if it has `tabindex` attribute set to `0`\non the host element or the `overlay` shadow DOM part.",
293
337
  "fieldName": "focusTrap",
294
338
  "inheritedFrom": {
295
339
  "name": "OverlayFocusMixin",
@@ -593,6 +637,24 @@
593
637
  "name": "rootMargin",
594
638
  "default": "`${-insetTop}px ${-insetRight}px ${-insetBottom}px ${-insetLeft}px`"
595
639
  },
640
+ {
641
+ "kind": "function",
642
+ "name": "shouldAnimate",
643
+ "parameters": [
644
+ {
645
+ "name": "element",
646
+ "type": {
647
+ "text": "HTMLElement"
648
+ }
649
+ }
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`.",
652
+ "return": {
653
+ "type": {
654
+ "text": "boolean"
655
+ }
656
+ }
657
+ },
596
658
  {
597
659
  "kind": "function",
598
660
  "name": "setOverlayStateAttribute",
@@ -631,6 +693,14 @@
631
693
  "module": "src/vaadin-overlay-utils.js"
632
694
  }
633
695
  },
696
+ {
697
+ "kind": "js",
698
+ "name": "shouldAnimate",
699
+ "declaration": {
700
+ "name": "shouldAnimate",
701
+ "module": "src/vaadin-overlay-utils.js"
702
+ }
703
+ },
634
704
  {
635
705
  "kind": "js",
636
706
  "name": "setOverlayStateAttribute",
@@ -650,6 +720,20 @@
650
720
  "description": "`<vaadin-overlay>` is a Web Component for creating overlays. The content of the overlay\ncan be populated imperatively by using `renderer` callback function.\n\n### Rendering\n\nThe renderer function provides `root`, `owner`, `model` arguments when applicable.\nGenerate DOM content by using `model` object properties if needed, append it to the `root`\nelement and control the state of the host element by accessing `owner`. Before generating new\ncontent, users are able to check if there is already content in `root` for reusing it.\n\n```html\n<vaadin-overlay id=\"overlay\"></vaadin-overlay>\n```\n```js\nconst overlay = document.querySelector('#overlay');\noverlay.renderer = function(root) {\n root.textContent = \"Overlay content\";\n};\n```\n\nRenderer is called on the opening of the overlay and each time the related model is updated.\nDOM generated during the renderer call can be reused\nin the next renderer call and will be provided with the `root` argument.\nOn first call it will be empty.\n\n### Styling\n\nThe following Shadow DOM parts are available for styling:\n\nPart name | Description\n-----------|---------------------------------------------------------|\n`backdrop` | Backdrop of the overlay\n`overlay` | Container for position/sizing/alignment of the content\n`content` | Content of the overlay\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n----------|------------\n`opening` | Applied just after the overlay is opened. You can apply a CSS animation for this state.\n`closing` | Applied just before the overlay is closed. You can apply a CSS animation for this state.\n\nThe following custom CSS properties are available for styling:\n\nCustom CSS property | Description | Default value\n---|---|---\n`--vaadin-overlay-viewport-bottom` | Bottom offset of the visible viewport area | `0` or detected offset\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
651
721
  "name": "Overlay",
652
722
  "members": [
723
+ {
724
+ "kind": "field",
725
+ "name": "autofocus",
726
+ "privacy": "public",
727
+ "type": {
728
+ "text": "boolean"
729
+ },
730
+ "description": "Set to true to move focus into the overlay automatically on open.\n\nFocus moves to the first tabbable element in the tab order. This\ncan be the overlay itself if it has `tabindex` attribute set to `0`\non the host element or the `overlay` shadow DOM part.",
731
+ "attribute": "autofocus",
732
+ "inheritedFrom": {
733
+ "name": "OverlayFocusMixin",
734
+ "module": "src/vaadin-overlay-focus-mixin.js"
735
+ }
736
+ },
653
737
  {
654
738
  "kind": "method",
655
739
  "name": "bringToFront",
@@ -682,7 +766,7 @@
682
766
  "type": {
683
767
  "text": "boolean"
684
768
  },
685
- "description": "When true, opening the overlay moves focus to the first focusable child,\nor to the overlay part with tabindex if there are no focusable children.",
769
+ "description": "Set to true to move focus into the overlay automatically on open\nand keep it inside: Tab and Shift+Tab cycle through the overlay's\ncontent until the overlay is closed.\n\nFocus moves to the first tabbable element in the tab order. This\ncan be the overlay itself if it has `tabindex` attribute set to `0`\non the host element or the `overlay` shadow DOM part.",
686
770
  "attribute": "focus-trap",
687
771
  "inheritedFrom": {
688
772
  "name": "OverlayFocusMixin",
@@ -937,12 +1021,24 @@
937
1021
  "tagName": "vaadin-overlay",
938
1022
  "customElement": true,
939
1023
  "attributes": [
1024
+ {
1025
+ "name": "autofocus",
1026
+ "type": {
1027
+ "text": "boolean"
1028
+ },
1029
+ "description": "Set to true to move focus into the overlay automatically on open.\n\nFocus moves to the first tabbable element in the tab order. This\ncan be the overlay itself if it has `tabindex` attribute set to `0`\non the host element or the `overlay` shadow DOM part.",
1030
+ "fieldName": "autofocus",
1031
+ "inheritedFrom": {
1032
+ "name": "OverlayFocusMixin",
1033
+ "module": "src/vaadin-overlay-focus-mixin.js"
1034
+ }
1035
+ },
940
1036
  {
941
1037
  "name": "focus-trap",
942
1038
  "type": {
943
1039
  "text": "boolean"
944
1040
  },
945
- "description": "When true, opening the overlay moves focus to the first focusable child,\nor to the overlay part with tabindex if there are no focusable children.",
1041
+ "description": "Set to true to move focus into the overlay automatically on open\nand keep it inside: Tab and Shift+Tab cycle through the overlay's\ncontent until the overlay is closed.\n\nFocus moves to the first tabbable element in the tab order. This\ncan be the overlay itself if it has `tabindex` attribute set to `0`\non the host element or the `overlay` shadow DOM part.",
946
1042
  "fieldName": "focusTrap",
947
1043
  "inheritedFrom": {
948
1044
  "name": "OverlayFocusMixin",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/overlay",
3
- "version": "25.3.0-alpha7",
3
+ "version": "25.3.0-alpha9",
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-alpha7",
38
- "@vaadin/component-base": "25.3.0-alpha7",
39
- "@vaadin/vaadin-themable-mixin": "25.3.0-alpha7",
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",
40
40
  "lit": "^3.0.0"
41
41
  },
42
42
  "devDependencies": {
43
- "@vaadin/aura": "25.3.0-alpha7",
44
- "@vaadin/chai-plugins": "25.3.0-alpha7",
45
- "@vaadin/test-runner-commands": "25.3.0-alpha7",
43
+ "@vaadin/aura": "25.3.0-alpha9",
44
+ "@vaadin/chai-plugins": "25.3.0-alpha9",
45
+ "@vaadin/test-runner-commands": "25.3.0-alpha9",
46
46
  "@vaadin/testing-helpers": "^2.0.0",
47
- "@vaadin/vaadin-lumo-styles": "25.3.0-alpha7",
47
+ "@vaadin/vaadin-lumo-styles": "25.3.0-alpha9",
48
48
  "sinon": "^22.0.0"
49
49
  },
50
50
  "customElements": "custom-elements.json",
51
- "gitHead": "ae7b9823df5598faebd7a482993029ee489c35ae"
51
+ "gitHead": "cb915ebde095ec5b94a87af93dd4530f51984c52"
52
52
  }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2026 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 overlayAnimationProperties: CSSResult;
9
+
10
+ export const overlayAnimationStyles: CSSResult;
@@ -0,0 +1,102 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2026 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { css, unsafeCSS } from 'lit';
7
+ import { registerCSSProperty } from '@vaadin/component-base/src/css-utils.js';
8
+
9
+ /**
10
+ * The custom properties that make up the overlay animation CSS API. Both the
11
+ * property registrations and the `overlayAnimationProperties` snippet below are
12
+ * derived from this list, so a new property only needs to be added here.
13
+ *
14
+ * Only the closed state is part of the API. The opened state is left out of the
15
+ * keyframes so that it comes from the part itself, see the keyframes below.
16
+ *
17
+ * `--vaadin-overlay-transform-closed` has no initial value, which makes it resolve
18
+ * to `none` in the keyframes unless a theme sets it.
19
+ */
20
+ const animationProperties = [
21
+ { name: '--vaadin-overlay-animation-duration', syntax: '<time>', initialValue: '0s' },
22
+ { name: '--vaadin-overlay-animation-delay', syntax: '<time>', initialValue: '0s' },
23
+ { name: '--vaadin-overlay-animation-timing-function', syntax: '*', initialValue: 'ease' },
24
+ { name: '--vaadin-overlay-opacity-closed', syntax: '<number>', initialValue: '0' },
25
+ { name: '--vaadin-overlay-translate-closed', syntax: '<length>+ | <percentage>+', initialValue: '0px' },
26
+ { name: '--vaadin-overlay-scale-closed', syntax: '<number> | <percentage>', initialValue: '1' },
27
+ { name: '--vaadin-overlay-transform-closed', syntax: '*' },
28
+ ];
29
+
30
+ animationProperties.forEach((property) => {
31
+ registerCSSProperty({ inherits: false, ...property });
32
+ });
33
+
34
+ /**
35
+ * The overlay animation properties as a set of `inherit` declarations. The properties are
36
+ * registered as non-inheriting, so components with more than one shadow root boundary
37
+ * between the host and the overlay need to forward them explicitly.
38
+ */
39
+ export const overlayAnimationProperties = unsafeCSS(
40
+ animationProperties.map(({ name }) => `${name}: inherit;`).join('\n'),
41
+ );
42
+
43
+ export const overlayAnimationStyles = css`
44
+ :host,
45
+ [part='overlay'],
46
+ [part='backdrop'] {
47
+ ${overlayAnimationProperties}
48
+ }
49
+
50
+ :host(:where([opening], [closing])) {
51
+ /* This empty animation only reports the state, the parts run the visible animation */
52
+ animation-name: --no-op;
53
+ animation-duration: var(--vaadin-overlay-animation-duration);
54
+ animation-delay: var(--vaadin-overlay-animation-delay);
55
+ }
56
+
57
+ :host(:where([closing])) [part='overlay'],
58
+ :host(:where([closing])) ::slotted(*) {
59
+ pointer-events: none !important;
60
+ }
61
+
62
+ :host(:where([opening], [closing])) :is([part='overlay'], [part='backdrop']) {
63
+ animation-name: --fade, --transform;
64
+ animation-duration: var(--vaadin-overlay-animation-duration);
65
+ animation-timing-function: var(--vaadin-overlay-animation-timing-function);
66
+ animation-delay: var(--vaadin-overlay-animation-delay);
67
+ /* Fill backwards only, so the closed value applies during the delay without overriding theme styles */
68
+ animation-fill-mode: backwards;
69
+
70
+ @media (prefers-reduced-motion) {
71
+ animation-name: --fade;
72
+ }
73
+ }
74
+
75
+ :host(:where([opening], [closing])) [part='backdrop'] {
76
+ animation-name: --fade;
77
+ animation-timing-function: linear;
78
+ --vaadin-overlay-opacity-closed: 0;
79
+ }
80
+
81
+ :host(:where([closing])) :is([part='overlay'], [part='backdrop']) {
82
+ animation-direction: reverse;
83
+ }
84
+
85
+ @keyframes --no-op {
86
+ }
87
+
88
+ /* Only the closed state is declared, so the animations end at the value the part already has */
89
+ @keyframes --transform {
90
+ 0% {
91
+ transform: var(--vaadin-overlay-transform-closed);
92
+ translate: var(--vaadin-overlay-translate-closed);
93
+ scale: var(--vaadin-overlay-scale-closed);
94
+ }
95
+ }
96
+
97
+ @keyframes --fade {
98
+ 0% {
99
+ opacity: var(--vaadin-overlay-opacity-closed);
100
+ }
101
+ }
102
+ `;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2026 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 overlayStyles: CSSResult[];
@@ -5,8 +5,9 @@
5
5
  */
6
6
  import '@vaadin/component-base/src/styles/style-props.js';
7
7
  import { css } from 'lit';
8
+ import { overlayAnimationStyles } from './vaadin-overlay-animation-base-styles.js';
8
9
 
9
- export const overlayStyles = css`
10
+ const overlayBase = css`
10
11
  :host {
11
12
  z-index: 200;
12
13
  position: fixed;
@@ -103,3 +104,5 @@ export const overlayStyles = css`
103
104
  }
104
105
  }
105
106
  `;
107
+
108
+ export const overlayStyles = [overlayBase, overlayAnimationStyles];
@@ -11,12 +11,27 @@ export declare function OverlayFocusMixin<T extends Constructor<HTMLElement>>(
11
11
 
12
12
  export declare class OverlayFocusMixinClass {
13
13
  /**
14
- * When true, opening the overlay moves focus to the first focusable child,
15
- * or to the overlay part with tabindex if there are no focusable children.
14
+ * Set to true to move focus into the overlay automatically on open
15
+ * and keep it inside: Tab and Shift+Tab cycle through the overlay's
16
+ * content until the overlay is closed.
17
+ *
18
+ * Focus moves to the first tabbable element in the tab order. This
19
+ * can be the overlay itself if it has `tabindex` attribute set to `0`
20
+ * on the host element or the `overlay` shadow DOM part.
21
+ *
16
22
  * @attr {boolean} focus-trap
17
23
  */
18
24
  focusTrap: boolean;
19
25
 
26
+ /**
27
+ * Set to true to move focus into the overlay automatically on open.
28
+ *
29
+ * Focus moves to the first tabbable element in the tab order. This
30
+ * can be the overlay itself if it has `tabindex` attribute set to `0`
31
+ * on the host element or the `overlay` shadow DOM part.
32
+ */
33
+ autofocus: boolean;
34
+
20
35
  /**
21
36
  * Set to true to enable restoring of focus when overlay is closed.
22
37
  * @attr {boolean} restore-focus-on-close
@@ -40,8 +55,9 @@ export declare class OverlayFocusMixinClass {
40
55
  protected _saveFocus(): void;
41
56
 
42
57
  /**
43
- * Sets up focus after the overlay opening has completed: traps focus
44
- * within the overlay if `focusTrap` is enabled.
58
+ * Sets up focus after the overlay opening has completed: moves focus into
59
+ * the overlay if `autofocus` is enabled, and traps focus within the overlay
60
+ * if `focusTrap` is enabled.
45
61
  */
46
62
  protected _initFocus(): void;
47
63
 
@@ -5,15 +5,27 @@
5
5
  */
6
6
  import { FocusRestorationController } from '@vaadin/a11y-base/src/focus-restoration-controller.js';
7
7
  import { FocusTrapController } from '@vaadin/a11y-base/src/focus-trap-controller.js';
8
- import { getDeepActiveElement, isElementHidden, isKeyboardActive } from '@vaadin/a11y-base/src/focus-utils.js';
8
+ import {
9
+ getDeepActiveElement,
10
+ getTabbableElements,
11
+ isElementFocused,
12
+ isElementHidden,
13
+ isKeyboardActive,
14
+ } from '@vaadin/a11y-base/src/focus-utils.js';
9
15
 
10
16
  export const OverlayFocusMixin = (superClass) =>
11
17
  class OverlayFocusMixin extends superClass {
12
18
  static get properties() {
13
19
  return {
14
20
  /**
15
- * When true, opening the overlay moves focus to the first focusable child,
16
- * or to the overlay part with tabindex if there are no focusable children.
21
+ * Set to true to move focus into the overlay automatically on open
22
+ * and keep it inside: Tab and Shift+Tab cycle through the overlay's
23
+ * content until the overlay is closed.
24
+ *
25
+ * Focus moves to the first tabbable element in the tab order. This
26
+ * can be the overlay itself if it has `tabindex` attribute set to `0`
27
+ * on the host element or the `overlay` shadow DOM part.
28
+ *
17
29
  * @attr {boolean} focus-trap
18
30
  */
19
31
  focusTrap: {
@@ -21,6 +33,18 @@ export const OverlayFocusMixin = (superClass) =>
21
33
  value: false,
22
34
  },
23
35
 
36
+ /**
37
+ * Set to true to move focus into the overlay automatically on open.
38
+ *
39
+ * Focus moves to the first tabbable element in the tab order. This
40
+ * can be the overlay itself if it has `tabindex` attribute set to `0`
41
+ * on the host element or the `overlay` shadow DOM part.
42
+ */
43
+ autofocus: {
44
+ type: Boolean,
45
+ value: false,
46
+ },
47
+
24
48
  /**
25
49
  * Set to true to enable restoring of focus when overlay is closed.
26
50
  * @attr {boolean} restore-focus-on-close
@@ -103,13 +127,25 @@ export const OverlayFocusMixin = (superClass) =>
103
127
  }
104
128
 
105
129
  /**
106
- * Sets up focus after the overlay opening has completed: traps focus
107
- * within the overlay if `focusTrap` is enabled.
130
+ * Sets up focus after the overlay opening has completed: moves focus into
131
+ * the overlay if `autofocus` is enabled, and traps focus within the overlay
132
+ * if `focusTrap` is enabled.
108
133
  *
109
134
  * @protected
110
135
  */
111
136
  _initFocus() {
112
- if (this.focusTrap && !isElementHidden(this._focusRoot)) {
137
+ if (isElementHidden(this._focusRoot)) {
138
+ return;
139
+ }
140
+
141
+ if (this.autofocus) {
142
+ const tabbables = getTabbableElements(this._focusRoot);
143
+ if (!tabbables.some(isElementFocused)) {
144
+ tabbables[0]?.focus({ focusVisible: isKeyboardActive() });
145
+ }
146
+ }
147
+
148
+ if (this.focusTrap) {
113
149
  this.__focusTrapController.trapFocus(this._focusRoot);
114
150
  }
115
151
  }
@@ -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 } from './vaadin-overlay-utils.js';
9
+ import { setOverlayStateAttribute, shouldAnimate } from './vaadin-overlay-utils.js';
10
10
 
11
11
  export const OverlayMixin = (superClass) =>
12
12
  class OverlayMixin extends OverlayFocusMixin(OverlayStackMixin(superClass)) {
@@ -133,14 +133,6 @@ export const OverlayMixin = (superClass) =>
133
133
  this.$.backdrop.addEventListener('click', () => {});
134
134
  }
135
135
 
136
- this.addEventListener('mouseup', () => {
137
- // In Chrome, focus moves to body on overlay content mousedown
138
- // See https://github.com/vaadin/flow-components/issues/5507
139
- if (document.activeElement === document.body && this.$.overlay.getAttribute('tabindex') === '0') {
140
- this.$.overlay.focus();
141
- }
142
- });
143
-
144
136
  this.addEventListener('animationcancel', () => {
145
137
  this._flushAnimation('opening');
146
138
  this._flushAnimation('closing');
@@ -405,14 +397,7 @@ export const OverlayMixin = (superClass) =>
405
397
  * @private
406
398
  */
407
399
  _shouldAnimate() {
408
- const style = getComputedStyle(this);
409
- const name = style.getPropertyValue('animation-name');
410
- const hasDuration = style
411
- .getPropertyValue('animation-duration')
412
- .split(',')
413
- .some((duration) => parseFloat(duration) > 0);
414
- const hidden = style.getPropertyValue('display') === 'none';
415
- return !hidden && name && name !== 'none' && hasDuration;
400
+ return shouldAnimate(this);
416
401
  }
417
402
 
418
403
  /**
@@ -12,6 +12,13 @@
12
12
  */
13
13
  export function observeMove(element: HTMLElement, callback: () => void): () => void;
14
14
 
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`.
19
+ */
20
+ export function shouldAnimate(element: HTMLElement): boolean;
21
+
15
22
  /**
16
23
  * Toggle the state attribute on the overlay element and also its owner element. This allows targeting state attributes
17
24
  * in the light DOM in case the overlay is in the shadow DOM of its owner.
@@ -85,6 +85,24 @@ export function observeMove(element, callback) {
85
85
  return cleanup;
86
86
  }
87
87
 
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`.
92
+ *
93
+ * @param {HTMLElement} element
94
+ * @return {boolean}
95
+ */
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;
104
+ }
105
+
88
106
  /**
89
107
  * Toggle the state attribute on the overlay element and also its owner element. This allows targeting state attributes
90
108
  * in the light DOM in case the overlay is in the shadow DOM of its owner.