@vaadin/overlay 25.3.1 → 25.3.2

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.
@@ -33,7 +33,7 @@
33
33
  "type": {
34
34
  "text": "boolean"
35
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.",
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.\n\nAn element inside the overlay that has `autofocus` set, such as\n`<vaadin-text-field autofocus>`, receives focus on open instead,\neven when this property is false.",
37
37
  "attribute": "autofocus"
38
38
  },
39
39
  {
@@ -73,7 +73,7 @@
73
73
  "type": {
74
74
  "text": "boolean"
75
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.",
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.\n\nAn element inside the overlay that has `autofocus` set, such as\n`<vaadin-text-field autofocus>`, receives focus on open instead,\neven when this property is false.",
77
77
  "fieldName": "autofocus"
78
78
  },
79
79
  {
@@ -135,7 +135,7 @@
135
135
  "type": {
136
136
  "text": "boolean"
137
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.",
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.\n\nAn element inside the overlay that has `autofocus` set, such as\n`<vaadin-text-field autofocus>`, receives focus on open instead,\neven when this property is false.",
139
139
  "attribute": "autofocus",
140
140
  "inheritedFrom": {
141
141
  "name": "OverlayFocusMixin",
@@ -321,7 +321,7 @@
321
321
  "type": {
322
322
  "text": "boolean"
323
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.",
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.\n\nAn element inside the overlay that has `autofocus` set, such as\n`<vaadin-text-field autofocus>`, receives focus on open instead,\neven when this property is false.",
325
325
  "fieldName": "autofocus",
326
326
  "inheritedFrom": {
327
327
  "name": "OverlayFocusMixin",
@@ -727,7 +727,7 @@
727
727
  "type": {
728
728
  "text": "boolean"
729
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.",
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.\n\nAn element inside the overlay that has `autofocus` set, such as\n`<vaadin-text-field autofocus>`, receives focus on open instead,\neven when this property is false.",
731
731
  "attribute": "autofocus",
732
732
  "inheritedFrom": {
733
733
  "name": "OverlayFocusMixin",
@@ -1027,7 +1027,7 @@
1027
1027
  "type": {
1028
1028
  "text": "boolean"
1029
1029
  },
1030
- "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
+ "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.\n\nAn element inside the overlay that has `autofocus` set, such as\n`<vaadin-text-field autofocus>`, receives focus on open instead,\neven when this property is false.",
1031
1031
  "fieldName": "autofocus",
1032
1032
  "inheritedFrom": {
1033
1033
  "name": "OverlayFocusMixin",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/overlay",
3
- "version": "25.3.1",
3
+ "version": "25.3.2",
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.1",
38
- "@vaadin/component-base": "~25.3.1",
39
- "@vaadin/vaadin-themable-mixin": "~25.3.1",
37
+ "@vaadin/a11y-base": "~25.3.2",
38
+ "@vaadin/component-base": "~25.3.2",
39
+ "@vaadin/vaadin-themable-mixin": "~25.3.2",
40
40
  "lit": "^3.0.0"
41
41
  },
42
42
  "devDependencies": {
43
- "@vaadin/aura": "~25.3.1",
44
- "@vaadin/chai-plugins": "~25.3.1",
45
- "@vaadin/test-runner-commands": "~25.3.1",
43
+ "@vaadin/aura": "~25.3.2",
44
+ "@vaadin/chai-plugins": "~25.3.2",
45
+ "@vaadin/test-runner-commands": "~25.3.2",
46
46
  "@vaadin/testing-helpers": "^2.0.0",
47
- "@vaadin/vaadin-lumo-styles": "~25.3.1",
47
+ "@vaadin/vaadin-lumo-styles": "~25.3.2",
48
48
  "sinon": "^22.0.0"
49
49
  },
50
50
  "customElements": "custom-elements.json",
51
- "gitHead": "a652d6071d7ad5add8465772f14f3efe633066a8"
51
+ "gitHead": "3f75254a3f77da3977cb79a77f549f37b8a5d54e"
52
52
  }
@@ -29,6 +29,10 @@ export declare class OverlayFocusMixinClass {
29
29
  * Focus moves to the first tabbable element in the tab order. This
30
30
  * can be the overlay itself if it has `tabindex` attribute set to `0`
31
31
  * on the host element or the `overlay` shadow DOM part.
32
+ *
33
+ * An element inside the overlay that has `autofocus` set, such as
34
+ * `<vaadin-text-field autofocus>`, receives focus on open instead,
35
+ * even when this property is false.
32
36
  */
33
37
  autofocus: boolean;
34
38
 
@@ -39,6 +39,10 @@ export const OverlayFocusMixin = (superClass) =>
39
39
  * Focus moves to the first tabbable element in the tab order. This
40
40
  * can be the overlay itself if it has `tabindex` attribute set to `0`
41
41
  * on the host element or the `overlay` shadow DOM part.
42
+ *
43
+ * An element inside the overlay that has `autofocus` set, such as
44
+ * `<vaadin-text-field autofocus>`, receives focus on open instead,
45
+ * even when this property is false.
42
46
  */
43
47
  autofocus: {
44
48
  type: Boolean,
@@ -65,11 +69,25 @@ export const OverlayFocusMixin = (superClass) =>
65
69
  };
66
70
  }
67
71
 
72
+ /**
73
+ * Whether the overlay moves, traps and restores focus. Override to return
74
+ * false in overlays that never do: focus properties are then ignored and
75
+ * the focus controllers are not created.
76
+ * @protected
77
+ */
78
+ static get manageFocus() {
79
+ return true;
80
+ }
81
+
68
82
  constructor() {
69
83
  super();
70
84
 
71
- this.__focusTrapController = new FocusTrapController(this);
72
- this.__focusRestorationController = new FocusRestorationController();
85
+ this.__manageFocus = this.constructor.manageFocus;
86
+
87
+ if (this.__manageFocus) {
88
+ this.__focusTrapController = new FocusTrapController(this);
89
+ this.__focusRestorationController = new FocusRestorationController();
90
+ }
73
91
  }
74
92
 
75
93
  /**
@@ -85,8 +103,10 @@ export const OverlayFocusMixin = (superClass) =>
85
103
  ready() {
86
104
  super.ready();
87
105
 
88
- this.addController(this.__focusTrapController);
89
- this.addController(this.__focusRestorationController);
106
+ if (this.__manageFocus) {
107
+ this.addController(this.__focusTrapController);
108
+ this.addController(this.__focusRestorationController);
109
+ }
90
110
  }
91
111
 
92
112
  /**
@@ -104,6 +124,10 @@ export const OverlayFocusMixin = (superClass) =>
104
124
  * @protected
105
125
  */
106
126
  _resetFocus() {
127
+ if (!this.__manageFocus) {
128
+ return;
129
+ }
130
+
107
131
  if (this.focusTrap) {
108
132
  this.__focusTrapController.releaseFocus();
109
133
  }
@@ -121,28 +145,32 @@ export const OverlayFocusMixin = (superClass) =>
121
145
  * @protected
122
146
  */
123
147
  _saveFocus() {
148
+ if (!this.__manageFocus) {
149
+ return;
150
+ }
151
+
124
152
  if (this.restoreFocusOnClose) {
125
153
  this.__focusRestorationController.saveFocus(this.restoreFocusNode);
126
154
  }
127
155
  }
128
156
 
129
157
  /**
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.
158
+ * Sets up focus after the overlay opening has completed: moves focus to
159
+ * the first element with `autofocus` inside the overlay, otherwise to the
160
+ * first tabbable element if the `autofocus` property is set, and traps
161
+ * focus if `focusTrap` is set.
133
162
  *
134
163
  * @protected
135
164
  */
136
165
  _initFocus() {
137
- if (isElementHidden(this._focusRoot)) {
166
+ if (!this.__manageFocus || isElementHidden(this._focusRoot)) {
138
167
  return;
139
168
  }
140
169
 
141
- if (this.autofocus) {
142
- const tabbables = getTabbableElements(this._focusRoot);
143
- if (!tabbables.some(isElementFocused)) {
144
- tabbables[0]?.focus({ focusVisible: isKeyboardActive() });
145
- }
170
+ const tabbables = getTabbableElements(this._focusRoot);
171
+ if (!tabbables.some(isElementFocused)) {
172
+ const target = tabbables.find((el) => this.#hasAutofocus(el)) ?? (this.autofocus ? tabbables[0] : null);
173
+ target?.focus({ focusVisible: isKeyboardActive() });
146
174
  }
147
175
 
148
176
  if (this.focusTrap) {
@@ -186,4 +214,27 @@ export const OverlayFocusMixin = (superClass) =>
186
214
  }
187
215
  return n === this._contentRoot;
188
216
  }
217
+
218
+ /**
219
+ * Returns true if the element has `autofocus`, or belongs to a custom
220
+ * element that has it (e.g. the input of `<vaadin-text-field autofocus>`).
221
+ * As with native `autofocus`, a plain `<div autofocus>` does not apply to
222
+ * its children. Stops at the focus root, whose `autofocus` refers to the overlay.
223
+ * Walks the flat tree, the same way tabbables are collected from the focus root,
224
+ * so it never leaves the overlay when content is slotted from the owner.
225
+ *
226
+ * @param {HTMLElement} element
227
+ * @return {boolean}
228
+ */
229
+ #hasAutofocus(element) {
230
+ const focusRoot = this._focusRoot;
231
+ let node = element;
232
+ while (node && node !== focusRoot && node !== this) {
233
+ if (node.autofocus && (node === element || customElements.get(node.localName))) {
234
+ return true;
235
+ }
236
+ node = node.assignedSlot || node.parentNode || node.host;
237
+ }
238
+ return false;
239
+ }
189
240
  };