@vaadin/overlay 24.1.0 → 24.1.1

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": "24.1.0",
3
+ "version": "24.1.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -36,17 +36,17 @@
36
36
  "dependencies": {
37
37
  "@open-wc/dedupe-mixin": "^1.3.0",
38
38
  "@polymer/polymer": "^3.0.0",
39
- "@vaadin/a11y-base": "~24.1.0",
40
- "@vaadin/component-base": "~24.1.0",
41
- "@vaadin/vaadin-lumo-styles": "~24.1.0",
42
- "@vaadin/vaadin-material-styles": "~24.1.0",
43
- "@vaadin/vaadin-themable-mixin": "~24.1.0"
39
+ "@vaadin/a11y-base": "~24.1.1",
40
+ "@vaadin/component-base": "~24.1.1",
41
+ "@vaadin/vaadin-lumo-styles": "~24.1.1",
42
+ "@vaadin/vaadin-material-styles": "~24.1.1",
43
+ "@vaadin/vaadin-themable-mixin": "~24.1.1"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@esm-bundle/chai": "^4.3.4",
47
- "@vaadin/testing-helpers": "^0.4.0",
47
+ "@vaadin/testing-helpers": "^0.4.2",
48
48
  "lit": "^2.0.0",
49
49
  "sinon": "^13.0.2"
50
50
  },
51
- "gitHead": "7fdfe7d5ceb4c305a894f8e9dc11e5b7d04cf1f2"
51
+ "gitHead": "c3a3d904885bd37ebb07a84b09617a340b4fab7e"
52
52
  }
@@ -36,12 +36,28 @@ export declare class OverlayFocusMixinClass {
36
36
  protected _resetFocus(): void;
37
37
 
38
38
  /**
39
- * Store previously focused node when the overlay starts to open.
39
+ * Save the previously focused node when the overlay starts to open.
40
40
  */
41
- protected _storeFocus(): void;
41
+ protected _saveFocus(): void;
42
42
 
43
43
  /**
44
44
  * Trap focus within the overlay after opening has completed.
45
45
  */
46
46
  protected _trapFocus(): void;
47
+
48
+ /**
49
+ * Returns true if focus is still inside the overlay or on the body element,
50
+ * otherwise false.
51
+ *
52
+ * Focus shouldn't be restored if it's been moved elsewhere by another
53
+ * component or as a result of a user interaction e.g. the user clicked
54
+ * on a button outside the overlay while the overlay was open.
55
+ */
56
+ protected _shouldRestoreFocus(): boolean;
57
+
58
+ /**
59
+ * Returns true if the overlay contains the given node,
60
+ * including those within shadow DOM trees.
61
+ */
62
+ protected _deepContains(node: Node): boolean;
47
63
  }
@@ -4,6 +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 { AriaModalController } from '@vaadin/a11y-base/src/aria-modal-controller.js';
7
+ import { FocusRestorationController } from '@vaadin/a11y-base/src/focus-restoration-controller.js';
7
8
  import { FocusTrapController } from '@vaadin/a11y-base/src/focus-trap-controller.js';
8
9
  import { getDeepActiveElement } from '@vaadin/a11y-base/src/focus-utils.js';
9
10
  import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
@@ -51,6 +52,7 @@ export const OverlayFocusMixin = (superClass) =>
51
52
 
52
53
  this.__ariaModalController = new AriaModalController(this);
53
54
  this.__focusTrapController = new FocusTrapController(this);
55
+ this.__focusRestorationController = new FocusRestorationController();
54
56
  }
55
57
 
56
58
  /** @protected */
@@ -59,6 +61,7 @@ export const OverlayFocusMixin = (superClass) =>
59
61
 
60
62
  this.addController(this.__ariaModalController);
61
63
  this.addController(this.__focusTrapController);
64
+ this.addController(this.__focusRestorationController);
62
65
  }
63
66
 
64
67
  /**
@@ -72,19 +75,19 @@ export const OverlayFocusMixin = (superClass) =>
72
75
  this.__focusTrapController.releaseFocus();
73
76
  }
74
77
 
75
- if (this.restoreFocusOnClose) {
76
- this.__restoreFocus();
78
+ if (this.restoreFocusOnClose && this._shouldRestoreFocus()) {
79
+ this.__focusRestorationController.restoreFocus();
77
80
  }
78
81
  }
79
82
 
80
83
  /**
81
- * Store previously focused node when the overlay starts to open.
84
+ * Save the previously focused node when the overlay starts to open.
82
85
  *
83
86
  * @protected
84
87
  */
85
- _storeFocus() {
88
+ _saveFocus() {
86
89
  if (this.restoreFocusOnClose) {
87
- this.__storeFocus();
90
+ this.__focusRestorationController.saveFocus(this.restoreFocusNode);
88
91
  }
89
92
  }
90
93
 
@@ -100,49 +103,40 @@ export const OverlayFocusMixin = (superClass) =>
100
103
  }
101
104
  }
102
105
 
103
- /** @private */
104
- __storeFocus() {
105
- // Store the focused node.
106
- this.__restoreFocusNode = getDeepActiveElement();
107
-
108
- // Determine and store the node that has the `focus-ring` attribute
109
- // in order to restore the attribute when the overlay closes.
110
- const restoreFocusNode = this.restoreFocusNode || this.__restoreFocusNode;
111
- if (restoreFocusNode) {
112
- const restoreFocusNodeHost = (restoreFocusNode.assignedSlot || restoreFocusNode).getRootNode().host;
113
- this.__restoreFocusRingNode = [restoreFocusNode, restoreFocusNodeHost].find((node) => {
114
- return node && node.hasAttribute('focus-ring');
115
- });
116
- }
117
- }
118
-
119
- /** @private */
120
- __restoreFocus() {
121
- // If the activeElement is `<body>` or inside the overlay,
122
- // we are allowed to restore the focus. In all the other
123
- // cases focus might have been moved elsewhere by another
124
- // component or by the user interaction (e.g. click on a
125
- // button outside the overlay).
106
+ /**
107
+ * Returns true if focus is still inside the overlay or on the body element,
108
+ * otherwise false.
109
+ *
110
+ * Focus shouldn't be restored if it's been moved elsewhere by another
111
+ * component or as a result of a user interaction e.g. the user clicked
112
+ * on a button outside the overlay while the overlay was open.
113
+ *
114
+ * @protected
115
+ * @return {boolean}
116
+ */
117
+ _shouldRestoreFocus() {
126
118
  const activeElement = getDeepActiveElement();
127
- if (activeElement !== document.body && !this._deepContains(activeElement)) {
128
- return;
129
- }
119
+ return activeElement === document.body || this._deepContains(activeElement);
120
+ }
130
121
 
131
- // Use restoreFocusNode if specified, otherwise fallback to the node
132
- // which was focused before opening the overlay.
133
- const restoreFocusNode = this.restoreFocusNode || this.__restoreFocusNode;
134
- if (restoreFocusNode) {
135
- // Focusing the restoreFocusNode doesn't always work synchronously on Firefox and Safari
136
- // (e.g. combo-box overlay close on outside click).
137
- setTimeout(() => restoreFocusNode.focus());
138
- this.__restoreFocusNode = null;
122
+ /**
123
+ * Returns true if the overlay contains the given node,
124
+ * including those within shadow DOM trees.
125
+ *
126
+ * @param {Node} node
127
+ * @return {boolean}
128
+ * @protected
129
+ */
130
+ _deepContains(node) {
131
+ if (this.contains(node)) {
132
+ return true;
139
133
  }
140
-
141
- // Restore the `focus-ring` attribute if it was present
142
- // when the overlay was opening.
143
- if (this.__restoreFocusRingNode) {
144
- this.__restoreFocusRingNode.setAttribute('focus-ring', '');
145
- this.__restoreFocusRingNode = null;
134
+ let n = node;
135
+ const doc = node.ownerDocument;
136
+ // Walk from node to `this` or `document`
137
+ while (n && n !== doc && n !== this) {
138
+ n = n.parentNode || n.host;
146
139
  }
140
+ return n === this;
147
141
  }
148
142
  };
@@ -449,7 +449,7 @@ class Overlay extends OverlayFocusMixin(ThemableMixin(DirMixin(PolymerElement)))
449
449
  /** @private */
450
450
  _openedChanged(opened, wasOpened) {
451
451
  if (opened) {
452
- this._storeFocus();
452
+ this._saveFocus();
453
453
 
454
454
  this._animatedOpening();
455
455
 
@@ -689,24 +689,6 @@ class Overlay extends OverlayFocusMixin(ThemableMixin(DirMixin(PolymerElement)))
689
689
  }
690
690
  }
691
691
 
692
- /**
693
- * @param {!Node} node
694
- * @return {boolean}
695
- * @private
696
- */
697
- _deepContains(node) {
698
- if (this.contains(node)) {
699
- return true;
700
- }
701
- let n = node;
702
- const doc = node.ownerDocument;
703
- // Walk from node to `this` or `document`
704
- while (n && n !== doc && n !== this) {
705
- n = n.parentNode || n.host;
706
- }
707
- return n === this;
708
- }
709
-
710
692
  /**
711
693
  * Brings the overlay as visually the frontmost one
712
694
  */