Hello! You can close this notification here:
diff --git a/packages/overlays/docs/40-system-configuration.md b/packages/overlays/docs/40-system-configuration.md
index 17efe6209..4df796fef 100644
--- a/packages/overlays/docs/40-system-configuration.md
+++ b/packages/overlays/docs/40-system-configuration.md
@@ -203,8 +203,8 @@ Boolean property. When true, will add a backdrop when the overlay is opened.
The backdrop styling can be configured by targeting the `.global-overlays .global-overlays__backdrop` css selector.
The backdrop animation can be configured by targeting the
-`.global-overlays .global-overlays__backdrop--fade-in` and
-`.global-overlays .global-overlays__backdrop--fade-out` css selector.
+`.global-overlays .global-overlays__backdrop--animation-in` and
+`.global-overlays .global-overlays__backdrop--animation-out` css selector.
This currently only supports CSS Animations, because it relies on the `animationend` event to add/remove classes.
```js preview-story
@@ -235,8 +235,8 @@ Boolean property. When true, will add a backdrop when the overlay is opened.
The backdrop styling can be configured by targeting the `.global-overlays .global-overlays__backdrop` css selector.
The backdrop animation can be configured by targeting the
-`.global-overlays .global-overlays__backdrop--fade-in` and
-`.global-overlays .global-overlays__backdrop--fade-out` css selector.
+`.global-overlays .global-overlays__backdrop--animation-in` and
+`.global-overlays .global-overlays__backdrop--animation-out` css selector.
This currently only supports CSS Animations, because it relies on the `animationend` event to add/remove classes.
```js preview-story
diff --git a/packages/overlays/docs/demo-overlay-backdrop.js b/packages/overlays/docs/demo-overlay-backdrop.js
new file mode 100644
index 000000000..3aa56e3b4
--- /dev/null
+++ b/packages/overlays/docs/demo-overlay-backdrop.js
@@ -0,0 +1,48 @@
+import { css, LitElement } from '@lion/core';
+
+/**
+ * @typedef {import('../types/OverlayConfig').OverlayConfig} OverlayConfig
+ */
+class DemoOverlayBackdrop extends LitElement {
+ static get styles() {
+ return css`
+ :host {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 1;
+ background-color: red;
+ opacity: 0.3;
+ display: none;
+ }
+
+ :host(.local-overlays__backdrop--visible) {
+ display: block;
+ }
+
+ :host(.local-overlays__backdrop--animation-in) {
+ animation: local-overlays-backdrop-fade-in 300ms;
+ }
+
+ :host(.local-overlays__backdrop--animation-out) {
+ animation: local-overlays-backdrop-fade-out 300ms;
+ opacity: 0;
+ }
+
+ @keyframes local-overlays-backdrop-fade-in {
+ from {
+ opacity: 0;
+ }
+ }
+
+ @keyframes local-overlays-backdrop-fade-out {
+ from {
+ opacity: 0.3;
+ }
+ }
+ `;
+ }
+}
+customElements.define('demo-overlay-backdrop', DemoOverlayBackdrop);
diff --git a/packages/overlays/docs/demo-overlay-system.js b/packages/overlays/docs/demo-overlay-system.js
index 4bcbfa85f..d94ae5499 100644
--- a/packages/overlays/docs/demo-overlay-system.js
+++ b/packages/overlays/docs/demo-overlay-system.js
@@ -40,7 +40,7 @@ class DemoOverlaySystem extends OverlayMixin(LitElement) {
render() {
return html`
-
+
diff --git a/packages/overlays/src/OverlayController.js b/packages/overlays/src/OverlayController.js
index e9d9bef3f..22f69a2f5 100644
--- a/packages/overlays/src/OverlayController.js
+++ b/packages/overlays/src/OverlayController.js
@@ -160,6 +160,8 @@ export class OverlayController extends EventTargetShim {
this.updateConfig(config);
this.__hasActiveTrapsKeyboardFocus = false;
this.__hasActiveBackdrop = true;
+ /** @type {HTMLElement | undefined} */
+ this.__backdropNodeToBeTornDown = undefined;
this.__escKeyHandler = this.__escKeyHandler.bind(this);
}
@@ -249,7 +251,7 @@ export class OverlayController extends EventTargetShim {
* @type {boolean}
*/
get hasBackdrop() {
- return /** @type {boolean} */ (this.config?.hasBackdrop);
+ return /** @type {boolean} */ (!!this.backdropNode || this.config?.hasBackdrop);
}
/**
@@ -418,7 +420,7 @@ export class OverlayController extends EventTargetShim {
*/
updateConfig(cfgToAdd) {
// Teardown all previous configs
- this._handleFeatures({ phase: 'teardown' });
+ this.teardown();
/** @type {OverlayConfig} */
this.__prevConfig = this.config || {};
@@ -616,7 +618,7 @@ export class OverlayController extends EventTargetShim {
}
}
} else if (phase === 'teardown') {
- this.__restorOriginalAttrs();
+ this.__restoreOriginalAttrs();
}
}
@@ -632,7 +634,7 @@ export class OverlayController extends EventTargetShim {
this.__originalAttrs.set(node, attrMap);
}
- __restorOriginalAttrs() {
+ __restoreOriginalAttrs() {
for (const [node, attrMap] of this.__originalAttrs) {
Object.entries(attrMap).forEach(([attrName, value]) => {
if (value !== null) {
@@ -796,16 +798,49 @@ export class OverlayController extends EventTargetShim {
}
/**
- * @param {{backdropNode:HTMLElement, contentNode:HTMLElement}} config
+ * @param {{backdropNode:HTMLElement, contentNode:HTMLElement}} hideConfig
*/
// eslint-disable-next-line class-methods-use-this, no-empty-function, no-unused-vars
- async transitionHide(config) {}
+ async transitionHide(hideConfig) {
+ if (hideConfig.backdropNode) {
+ hideConfig.backdropNode.classList.remove(
+ `${this.placementMode}-overlays__backdrop--animation-in`,
+ );
+ /** @type {(ev:AnimationEvent) => void} */
+ let afterFadeOut;
+ hideConfig.backdropNode.classList.add(
+ `${this.placementMode}-overlays__backdrop--animation-out`,
+ );
+ this.__backdropAnimation = new Promise(resolve => {
+ afterFadeOut = () => {
+ if (hideConfig.backdropNode) {
+ hideConfig.backdropNode.classList.remove(
+ `${this.placementMode}-overlays__backdrop--animation-out`,
+ );
+ hideConfig.backdropNode.classList.remove(
+ `${this.placementMode}-overlays__backdrop--visible`,
+ );
+ hideConfig.backdropNode.removeEventListener('animationend', afterFadeOut);
+ }
+ resolve();
+ };
+ });
+ // @ts-expect-error
+ hideConfig.backdropNode.addEventListener('animationend', afterFadeOut);
+ }
+ }
/**
- * @param {{backdropNode:HTMLElement, contentNode:HTMLElement}} config
+ * @param {{backdropNode:HTMLElement, contentNode:HTMLElement}} showConfig
*/
// eslint-disable-next-line class-methods-use-this, no-empty-function, no-unused-vars
- async transitionShow(config) {}
+ async transitionShow(showConfig) {
+ if (showConfig.backdropNode) {
+ showConfig.backdropNode.classList.add(
+ `${this.placementMode}-overlays__backdrop--animation-in`,
+ );
+ }
+ }
_restoreFocus() {
// We only are allowed to move focus if we (still) 'own' it.
@@ -891,97 +926,58 @@ export class OverlayController extends EventTargetShim {
/**
* Sets up backdrop on the given overlay. If there was a backdrop on another element
- * it is removed. Otherwise this is the first time displaying a backdrop, so a fade-in
+ * it is removed. Otherwise this is the first time displaying a backdrop, so a animation-in
* animation is played.
* @param {{ animation?: boolean, phase: OverlayPhase }} config
*/
- _handleBackdrop({ animation = true, phase }) {
- if (this.placementMode === 'local') {
- switch (phase) {
- case 'init':
- if (!this.backdropNode) {
- this.__backdropNode = document.createElement('div');
- /** @type {HTMLElement} */
- (this.backdropNode).classList.add('local-overlays__backdrop');
- }
- this.backdropNode.slot = '_overlay-shadow-outlet';
- /** @type {HTMLElement} */
- (this.contentNode.parentNode).insertBefore(this.backdropNode, this.contentNode);
- break;
- case 'show':
- this.__hasActiveBackdrop = true;
- break;
- case 'hide':
- if (!this.backdropNode) {
- return;
- }
- this.__hasActiveBackdrop = false;
- break;
- case 'teardown':
- if (!this.backdropNode || !this.backdropNode.parentNode) {
- return;
- }
- this.backdropNode.parentNode.removeChild(this.backdropNode);
- this.__backdropNode = undefined;
- break;
- /* no default */
- }
- return;
- }
+ _handleBackdrop({ phase }) {
switch (phase) {
- case 'init':
- this.__backdropNode = document.createElement('div');
- this.backdropNode.classList.add('global-overlays__backdrop');
- /** @type {HTMLElement} */
- (this.contentWrapperNode.parentElement).insertBefore(
- this.backdropNode,
- this.contentWrapperNode,
- );
- break;
- case 'show':
- this.backdropNode.classList.add('global-overlays__backdrop--visible');
- if (animation === true) {
- this.backdropNode.classList.add('global-overlays__backdrop--fade-in');
+ case 'init': {
+ if (!this.backdropNode) {
+ this.__backdropNode = document.createElement('div');
+ /** @type {HTMLElement} */
+ (this.backdropNode).slot = 'backdrop';
+ /** @type {HTMLElement} */
+ (this.backdropNode).classList.add(`${this.placementMode}-overlays__backdrop`);
}
+
+ let insertionAnchor = /** @type {HTMLElement} */ (this.contentNode.parentNode);
+ let insertionBefore = this.contentNode;
+ if (this.placementMode === 'global') {
+ insertionAnchor = /** @type {HTMLElement} */ (this.contentWrapperNode.parentElement);
+ insertionBefore = this.contentWrapperNode;
+ }
+ insertionAnchor.insertBefore(this.backdropNode, insertionBefore);
+ break;
+ }
+ case 'show':
+ this.backdropNode.classList.add(`${this.placementMode}-overlays__backdrop--visible`);
this.__hasActiveBackdrop = true;
break;
case 'hide':
if (!this.backdropNode) {
return;
}
- this.backdropNode.classList.remove('global-overlays__backdrop--fade-in');
-
- if (animation) {
- /** @type {(ev:AnimationEvent) => void} */
- let afterFadeOut;
- this.backdropNode.classList.add('global-overlays__backdrop--fade-out');
- this.__backDropAnimation = new Promise(resolve => {
- afterFadeOut = () => {
- this.backdropNode.classList.remove('global-overlays__backdrop--fade-out');
- this.backdropNode.classList.remove('global-overlays__backdrop--visible');
- this.backdropNode.removeEventListener('animationend', afterFadeOut);
- resolve();
- };
- });
- // @ts-expect-error
- this.backdropNode.addEventListener('animationend', afterFadeOut);
- } else {
- this.backdropNode.classList.remove('global-overlays__backdrop--visible');
- }
this.__hasActiveBackdrop = false;
break;
case 'teardown':
if (!this.backdropNode || !this.backdropNode.parentNode) {
return;
}
- if (animation && this.__backDropAnimation) {
- this.__backDropAnimation.then(() => {
- /** @type {HTMLElement} */
- (this.backdropNode.parentNode).removeChild(this.backdropNode);
+ if (this.__backdropAnimation) {
+ this.__backdropNodeToBeTornDown = this.backdropNode;
+
+ this.__backdropAnimation.then(() => {
+ if (this.__backdropNodeToBeTornDown) {
+ /** @type {HTMLElement} */ (this.__backdropNodeToBeTornDown.parentNode).removeChild(
+ this.__backdropNodeToBeTornDown,
+ );
+ }
});
} else {
this.backdropNode.parentNode.removeChild(this.backdropNode);
}
+ this.__backdropNode = undefined;
break;
/* no default */
}
diff --git a/packages/overlays/src/OverlayMixin.js b/packages/overlays/src/OverlayMixin.js
index 39f528fa3..f656ab722 100644
--- a/packages/overlays/src/OverlayMixin.js
+++ b/packages/overlays/src/OverlayMixin.js
@@ -183,9 +183,9 @@ export const OverlayMixinImplementation = superclass =>
get _overlayContentNode() {
if (!this._cachedOverlayContentNode) {
- this._cachedOverlayContentNode = Array.from(this.children).find(
- child => child.slot === 'content',
- );
+ this._cachedOverlayContentNode =
+ Array.from(this.children).find(child => child.slot === 'content') ||
+ this.config.contentNode;
}
return this._cachedOverlayContentNode;
}
diff --git a/packages/overlays/src/globalOverlaysStyle.js b/packages/overlays/src/globalOverlaysStyle.js
index d112f77fb..7325d1305 100644
--- a/packages/overlays/src/globalOverlaysStyle.js
+++ b/packages/overlays/src/globalOverlaysStyle.js
@@ -85,11 +85,11 @@ export const globalOverlaysStyle = css`
display: block;
}
- .global-overlays .global-overlays__backdrop--fade-in {
+ .global-overlays .global-overlays__backdrop--animation-in {
animation: global-overlays-backdrop-fade-in 300ms;
}
- .global-overlays .global-overlays__backdrop--fade-out {
+ .global-overlays .global-overlays__backdrop--animation-out {
animation: global-overlays-backdrop-fade-out 300ms;
opacity: 0;
}