@vaadin/overlay
Advanced tools
Comparing version 24.1.0 to 24.1.1
{ | ||
"name": "@vaadin/overlay", | ||
"version": "24.1.0", | ||
"version": "24.1.1", | ||
"publishConfig": { | ||
@@ -39,15 +39,15 @@ "access": "public" | ||
"@polymer/polymer": "^3.0.0", | ||
"@vaadin/a11y-base": "~24.1.0", | ||
"@vaadin/component-base": "~24.1.0", | ||
"@vaadin/vaadin-lumo-styles": "~24.1.0", | ||
"@vaadin/vaadin-material-styles": "~24.1.0", | ||
"@vaadin/vaadin-themable-mixin": "~24.1.0" | ||
"@vaadin/a11y-base": "~24.1.1", | ||
"@vaadin/component-base": "~24.1.1", | ||
"@vaadin/vaadin-lumo-styles": "~24.1.1", | ||
"@vaadin/vaadin-material-styles": "~24.1.1", | ||
"@vaadin/vaadin-themable-mixin": "~24.1.1" | ||
}, | ||
"devDependencies": { | ||
"@esm-bundle/chai": "^4.3.4", | ||
"@vaadin/testing-helpers": "^0.4.0", | ||
"@vaadin/testing-helpers": "^0.4.2", | ||
"lit": "^2.0.0", | ||
"sinon": "^13.0.2" | ||
}, | ||
"gitHead": "7fdfe7d5ceb4c305a894f8e9dc11e5b7d04cf1f2" | ||
"gitHead": "c3a3d904885bd37ebb07a84b09617a340b4fab7e" | ||
} |
@@ -39,5 +39,5 @@ /** | ||
/** | ||
* Store previously focused node when the overlay starts to open. | ||
* Save the previously focused node when the overlay starts to open. | ||
*/ | ||
protected _storeFocus(): void; | ||
protected _saveFocus(): void; | ||
@@ -48,2 +48,18 @@ /** | ||
protected _trapFocus(): void; | ||
/** | ||
* Returns true if focus is still inside the overlay or on the body element, | ||
* otherwise false. | ||
* | ||
* Focus shouldn't be restored if it's been moved elsewhere by another | ||
* component or as a result of a user interaction e.g. the user clicked | ||
* on a button outside the overlay while the overlay was open. | ||
*/ | ||
protected _shouldRestoreFocus(): boolean; | ||
/** | ||
* Returns true if the overlay contains the given node, | ||
* including those within shadow DOM trees. | ||
*/ | ||
protected _deepContains(node: Node): boolean; | ||
} |
@@ -7,2 +7,3 @@ /** | ||
import { AriaModalController } from '@vaadin/a11y-base/src/aria-modal-controller.js'; | ||
import { FocusRestorationController } from '@vaadin/a11y-base/src/focus-restoration-controller.js'; | ||
import { FocusTrapController } from '@vaadin/a11y-base/src/focus-trap-controller.js'; | ||
@@ -55,2 +56,3 @@ import { getDeepActiveElement } from '@vaadin/a11y-base/src/focus-utils.js'; | ||
this.__focusTrapController = new FocusTrapController(this); | ||
this.__focusRestorationController = new FocusRestorationController(); | ||
} | ||
@@ -64,2 +66,3 @@ | ||
this.addController(this.__focusTrapController); | ||
this.addController(this.__focusRestorationController); | ||
} | ||
@@ -78,4 +81,4 @@ | ||
if (this.restoreFocusOnClose) { | ||
this.__restoreFocus(); | ||
if (this.restoreFocusOnClose && this._shouldRestoreFocus()) { | ||
this.__focusRestorationController.restoreFocus(); | ||
} | ||
@@ -85,9 +88,9 @@ } | ||
/** | ||
* Store previously focused node when the overlay starts to open. | ||
* Save the previously focused node when the overlay starts to open. | ||
* | ||
* @protected | ||
*/ | ||
_storeFocus() { | ||
_saveFocus() { | ||
if (this.restoreFocusOnClose) { | ||
this.__storeFocus(); | ||
this.__focusRestorationController.saveFocus(this.restoreFocusNode); | ||
} | ||
@@ -108,47 +111,38 @@ } | ||
/** @private */ | ||
__storeFocus() { | ||
// Store the focused node. | ||
this.__restoreFocusNode = getDeepActiveElement(); | ||
// Determine and store the node that has the `focus-ring` attribute | ||
// in order to restore the attribute when the overlay closes. | ||
const restoreFocusNode = this.restoreFocusNode || this.__restoreFocusNode; | ||
if (restoreFocusNode) { | ||
const restoreFocusNodeHost = (restoreFocusNode.assignedSlot || restoreFocusNode).getRootNode().host; | ||
this.__restoreFocusRingNode = [restoreFocusNode, restoreFocusNodeHost].find((node) => { | ||
return node && node.hasAttribute('focus-ring'); | ||
}); | ||
} | ||
/** | ||
* Returns true if focus is still inside the overlay or on the body element, | ||
* otherwise false. | ||
* | ||
* Focus shouldn't be restored if it's been moved elsewhere by another | ||
* component or as a result of a user interaction e.g. the user clicked | ||
* on a button outside the overlay while the overlay was open. | ||
* | ||
* @protected | ||
* @return {boolean} | ||
*/ | ||
_shouldRestoreFocus() { | ||
const activeElement = getDeepActiveElement(); | ||
return activeElement === document.body || this._deepContains(activeElement); | ||
} | ||
/** @private */ | ||
__restoreFocus() { | ||
// If the activeElement is `<body>` or inside the overlay, | ||
// we are allowed to restore the focus. In all the other | ||
// cases focus might have been moved elsewhere by another | ||
// component or by the user interaction (e.g. click on a | ||
// button outside the overlay). | ||
const activeElement = getDeepActiveElement(); | ||
if (activeElement !== document.body && !this._deepContains(activeElement)) { | ||
return; | ||
/** | ||
* Returns true if the overlay contains the given node, | ||
* including those within shadow DOM trees. | ||
* | ||
* @param {Node} node | ||
* @return {boolean} | ||
* @protected | ||
*/ | ||
_deepContains(node) { | ||
if (this.contains(node)) { | ||
return true; | ||
} | ||
// Use restoreFocusNode if specified, otherwise fallback to the node | ||
// which was focused before opening the overlay. | ||
const restoreFocusNode = this.restoreFocusNode || this.__restoreFocusNode; | ||
if (restoreFocusNode) { | ||
// Focusing the restoreFocusNode doesn't always work synchronously on Firefox and Safari | ||
// (e.g. combo-box overlay close on outside click). | ||
setTimeout(() => restoreFocusNode.focus()); | ||
this.__restoreFocusNode = null; | ||
let n = node; | ||
const doc = node.ownerDocument; | ||
// Walk from node to `this` or `document` | ||
while (n && n !== doc && n !== this) { | ||
n = n.parentNode || n.host; | ||
} | ||
// Restore the `focus-ring` attribute if it was present | ||
// when the overlay was opening. | ||
if (this.__restoreFocusRingNode) { | ||
this.__restoreFocusRingNode.setAttribute('focus-ring', ''); | ||
this.__restoreFocusRingNode = null; | ||
} | ||
return n === this; | ||
} | ||
}; |
@@ -452,3 +452,3 @@ /** | ||
if (opened) { | ||
this._storeFocus(); | ||
this._saveFocus(); | ||
@@ -694,20 +694,2 @@ this._animatedOpening(); | ||
/** | ||
* @param {!Node} node | ||
* @return {boolean} | ||
* @private | ||
*/ | ||
_deepContains(node) { | ||
if (this.contains(node)) { | ||
return true; | ||
} | ||
let n = node; | ||
const doc = node.ownerDocument; | ||
// Walk from node to `this` or `document` | ||
while (n && n !== doc && n !== this) { | ||
n = n.parentNode || n.host; | ||
} | ||
return n === this; | ||
} | ||
/** | ||
* Brings the overlay as visually the frontmost one | ||
@@ -714,0 +696,0 @@ */ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
64246
1400