feat(overlays): simplify backdrop API, allow animated backdrop for local
This commit is contained in:
parent
b5e7df3ed9
commit
d83f7fc5ce
7 changed files with 213 additions and 122 deletions
12
.changeset/cool-panthers-design.md
Normal file
12
.changeset/cool-panthers-design.md
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
'@lion/overlays': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
⚠️ BREAKING CHANGE:
|
||||||
|
|
||||||
|
Fixed a few problems with the backdropNode and contentNode where they were not torn down properly.
|
||||||
|
Simplified the handleBackdrop code to work for both local and global.
|
||||||
|
Local overlay backdrop can now be animated.
|
||||||
|
Added more demos and docs for backdrop.
|
||||||
|
|
||||||
|
The breaking changes lie in the fact that the backdrop style classes are now prefixed 'local'/'global' respectively, instead of always 'global' and the class name suffixes for the `backdropNode` have changed from `fade-in`/`fade-out` to `animation-in`/`animation-out`, as not all animations are fades.
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
```js script
|
```js script
|
||||||
import { html } from 'lit-html';
|
import { html } from 'lit-html';
|
||||||
import { render, LitElement } from '@lion/core';
|
import { render, LitElement } from '@lion/core';
|
||||||
|
import { renderLitAsNode } from '@lion/helpers';
|
||||||
import {
|
import {
|
||||||
ArrowMixin,
|
ArrowMixin,
|
||||||
OverlayMixin,
|
OverlayMixin,
|
||||||
|
|
@ -14,6 +15,7 @@ import {
|
||||||
} from '../index.js';
|
} from '../index.js';
|
||||||
|
|
||||||
import '../docs/demo-overlay-system.js';
|
import '../docs/demo-overlay-system.js';
|
||||||
|
import '../docs/demo-overlay-backdrop.js';
|
||||||
import '../docs/applyDemoOverlayStyles.js';
|
import '../docs/applyDemoOverlayStyles.js';
|
||||||
import { ref as r } from '../docs/directives/ref.js';
|
import { ref as r } from '../docs/directives/ref.js';
|
||||||
|
|
||||||
|
|
@ -29,7 +31,7 @@ On top of this, the system was built having accessibility in mind.
|
||||||
|
|
||||||
For a detailed rationale, please consult [Rationale](/?path=/docs/overlays-system-rationale--page).
|
For a detailed rationale, please consult [Rationale](/?path=/docs/overlays-system-rationale--page).
|
||||||
|
|
||||||
```js story
|
```js preview-story
|
||||||
export const main = () => html`
|
export const main = () => html`
|
||||||
<demo-overlay-system>
|
<demo-overlay-system>
|
||||||
<button slot="invoker">Click me to open the overlay!</button>
|
<button slot="invoker">Click me to open the overlay!</button>
|
||||||
|
|
@ -151,6 +153,100 @@ or declaratively in your template with the `.config` property
|
||||||
</demo-overlay-system>
|
</demo-overlay-system>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Backdrop
|
||||||
|
|
||||||
|
There are multiple ways to pass a backdrop node for your overlay.
|
||||||
|
|
||||||
|
The easiest way is declarative. This can be achieved by adding a `<slot name="backdrop">` to your `render` method. The component user can then insert a backdrop slottable declaratively:
|
||||||
|
|
||||||
|
```js preview-story
|
||||||
|
export const backdrop = () => html`
|
||||||
|
<demo-overlay-system .config=${{ ...withModalDialogConfig() }}>
|
||||||
|
<demo-overlay-backdrop slot="backdrop"></demo-overlay-backdrop>
|
||||||
|
<button slot="invoker">Click me to open the overlay!</button>
|
||||||
|
<div slot="content" class="demo-overlay">
|
||||||
|
Hello! You can close this notification here:
|
||||||
|
<button @click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}>
|
||||||
|
⨯
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</demo-overlay-system>
|
||||||
|
`;
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also pass a backdropNode imperatively to the OverlayConfig. Either use `hasBackdrop: true`, which will spawn a default `backdropNode`.
|
||||||
|
For more control, pass a `backdropNode` yourself, e.g. a webcomponent so you can easily encapsulate styles.
|
||||||
|
|
||||||
|
```js preview-story
|
||||||
|
export const backdropImperative = () => {
|
||||||
|
const backdropNode = document.createElement('demo-overlay-backdrop');
|
||||||
|
return html`
|
||||||
|
<demo-overlay-system .config=${{ ...withModalDialogConfig(), backdropNode }}>
|
||||||
|
<button slot="invoker">Click me to open the overlay!</button>
|
||||||
|
<div slot="content" class="demo-overlay">
|
||||||
|
Hello! You can close this notification here:
|
||||||
|
<button
|
||||||
|
@click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
|
||||||
|
>
|
||||||
|
⨯
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</demo-overlay-system>
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Backdrop animation
|
||||||
|
|
||||||
|
By default our overlay system comes with a backdrop animation.
|
||||||
|
This will add `global-overlays__backdrop--animation-in` and `global-overlays__backdrop--animation-out` classes to your backdrop node.
|
||||||
|
If you have `placementMode: 'local'` it will replace those `global` strings in the CSS classes with `local`.
|
||||||
|
|
||||||
|
It expects from you that you act on these classes in your CSS with an animation. For example if you have your own backdrop webcomponent (to encapsulate styles):
|
||||||
|
|
||||||
|
```css
|
||||||
|
: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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Under the hood, the OverlayController listens to `animationend` event, only then it will remove the animation-out/animation-in classes.
|
||||||
|
|
||||||
|
> If you don't intend on having a backdrop animation at all, as a subclasser you should override `transitionHide` and `transitionShow` OverlayMixin methods.
|
||||||
|
> Otherwise the `hide` will await an `animationend` event that will never happen.
|
||||||
|
|
||||||
|
```js preview-story
|
||||||
|
export const backdropAnimation = () => html`
|
||||||
|
<demo-overlay-system .config=${{ ...withModalDialogConfig() }}>
|
||||||
|
<button slot="invoker">Click me to open the overlay!</button>
|
||||||
|
<demo-overlay-backdrop slot="backdrop"></demo-overlay-backdrop>
|
||||||
|
<div slot="content" class="demo-overlay">
|
||||||
|
Hello! You can close this notification here:
|
||||||
|
<button @click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}>
|
||||||
|
⨯
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</demo-overlay-system>
|
||||||
|
`;
|
||||||
|
```
|
||||||
|
|
||||||
### Responsive switching
|
### Responsive switching
|
||||||
|
|
||||||
Currently we support switching between overlay configurations.
|
Currently we support switching between overlay configurations.
|
||||||
|
|
@ -174,12 +270,6 @@ export const responsiveSwitching = () => html`
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<button slot="invoker">Click me to open the overlay!</button>
|
<button slot="invoker">Click me to open the overlay!</button>
|
||||||
<div slot="content" class="demo-overlay">
|
|
||||||
Hello! You can close this notification here:
|
|
||||||
<button @click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}>
|
|
||||||
⨯
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</demo-overlay-system>
|
</demo-overlay-system>
|
||||||
`;
|
`;
|
||||||
```
|
```
|
||||||
|
|
@ -454,73 +544,9 @@ Here is the example below
|
||||||
|
|
||||||
```js preview-story
|
```js preview-story
|
||||||
export const localBackdrop = () => {
|
export const localBackdrop = () => {
|
||||||
let backdropNode = document.createElement('div');
|
|
||||||
backdropNode.classList.add('local-backdrop-01');
|
|
||||||
return html`
|
return html`
|
||||||
<style>
|
<demo-overlay-system .config=${{ placementMode: 'local' }}>
|
||||||
.local-backdrop-01 {
|
<demo-overlay-backdrop slot="backdrop"></demo-overlay-backdrop>
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
z-index: 1;
|
|
||||||
background-color: red;
|
|
||||||
opacity: 0.3;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<demo-overlay-system
|
|
||||||
@before-opened=${e => (backdropNode.style.display = 'block')}
|
|
||||||
@before-closed=${e => (backdropNode.style.display = 'none')}
|
|
||||||
.config=${{ hasBackdrop: true, placementMode: 'local', backdropNode }}
|
|
||||||
>
|
|
||||||
<button slot="invoker">Click me to open the overlay!</button>
|
|
||||||
<div slot="content" class="demo-overlay">
|
|
||||||
Hello! You can close this notification here:
|
|
||||||
<button
|
|
||||||
@click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
|
|
||||||
>
|
|
||||||
⨯
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</demo-overlay-system>
|
|
||||||
`;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## Declarative Local Backdrop
|
|
||||||
|
|
||||||
Another way to add custom backdrop is declaratively add an element with `slot="backdrop"`.
|
|
||||||
|
|
||||||
```js preview-story
|
|
||||||
export const declarativeLocalBackdrop = () => {
|
|
||||||
const beforeOpened = () => {
|
|
||||||
document.querySelector('.local-backdrop-02').style.display = 'block';
|
|
||||||
};
|
|
||||||
const beforeClosed = () => {
|
|
||||||
document.querySelector('.local-backdrop-02').style.display = 'none';
|
|
||||||
};
|
|
||||||
return html`
|
|
||||||
<style>
|
|
||||||
.local-backdrop-02 {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
z-index: 1;
|
|
||||||
background-color: red;
|
|
||||||
opacity: 0.3;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<demo-overlay-system
|
|
||||||
@before-opened=${beforeOpened}
|
|
||||||
@before-closed=${beforeClosed}
|
|
||||||
.config=${{ hasBackdrop: true, placementMode: 'local' }}
|
|
||||||
>
|
|
||||||
<div slot="backdrop" class="local-backdrop-02"></div>
|
|
||||||
<button slot="invoker">Click me to open the overlay!</button>
|
<button slot="invoker">Click me to open the overlay!</button>
|
||||||
<div slot="content" class="demo-overlay">
|
<div slot="content" class="demo-overlay">
|
||||||
Hello! You can close this notification here:
|
Hello! You can close this notification here:
|
||||||
|
|
|
||||||
|
|
@ -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 styling can be configured by targeting the `.global-overlays .global-overlays__backdrop` css selector.
|
||||||
|
|
||||||
The backdrop animation can be configured by targeting the
|
The backdrop animation can be configured by targeting the
|
||||||
`.global-overlays .global-overlays__backdrop--fade-in` and
|
`.global-overlays .global-overlays__backdrop--animation-in` and
|
||||||
`.global-overlays .global-overlays__backdrop--fade-out` css selector.
|
`.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.
|
This currently only supports CSS Animations, because it relies on the `animationend` event to add/remove classes.
|
||||||
|
|
||||||
```js preview-story
|
```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 styling can be configured by targeting the `.global-overlays .global-overlays__backdrop` css selector.
|
||||||
|
|
||||||
The backdrop animation can be configured by targeting the
|
The backdrop animation can be configured by targeting the
|
||||||
`.global-overlays .global-overlays__backdrop--fade-in` and
|
`.global-overlays .global-overlays__backdrop--animation-in` and
|
||||||
`.global-overlays .global-overlays__backdrop--fade-out` css selector.
|
`.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.
|
This currently only supports CSS Animations, because it relies on the `animationend` event to add/remove classes.
|
||||||
|
|
||||||
```js preview-story
|
```js preview-story
|
||||||
|
|
|
||||||
48
packages/overlays/docs/demo-overlay-backdrop.js
Normal file
48
packages/overlays/docs/demo-overlay-backdrop.js
Normal file
|
|
@ -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);
|
||||||
|
|
@ -40,7 +40,7 @@ class DemoOverlaySystem extends OverlayMixin(LitElement) {
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<slot name="invoker"></slot>
|
<slot name="invoker"></slot>
|
||||||
<slot name="_overlay-shadow-outlet"></slot>
|
<slot name="backdrop"></slot>
|
||||||
<div id="overlay-content-node-wrapper">
|
<div id="overlay-content-node-wrapper">
|
||||||
<slot name="content"></slot>
|
<slot name="content"></slot>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -251,7 +251,7 @@ export class OverlayController extends EventTargetShim {
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
get hasBackdrop() {
|
get hasBackdrop() {
|
||||||
return /** @type {boolean} */ (this.config?.hasBackdrop);
|
return /** @type {boolean} */ (!!this.backdropNode || this.config?.hasBackdrop);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -618,7 +618,7 @@ export class OverlayController extends EventTargetShim {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (phase === 'teardown') {
|
} else if (phase === 'teardown') {
|
||||||
this.__restorOriginalAttrs();
|
this.__restoreOriginalAttrs();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -634,7 +634,7 @@ export class OverlayController extends EventTargetShim {
|
||||||
this.__originalAttrs.set(node, attrMap);
|
this.__originalAttrs.set(node, attrMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
__restorOriginalAttrs() {
|
__restoreOriginalAttrs() {
|
||||||
for (const [node, attrMap] of this.__originalAttrs) {
|
for (const [node, attrMap] of this.__originalAttrs) {
|
||||||
Object.entries(attrMap).forEach(([attrName, value]) => {
|
Object.entries(attrMap).forEach(([attrName, value]) => {
|
||||||
if (value !== null) {
|
if (value !== null) {
|
||||||
|
|
@ -798,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
|
// 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
|
// 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() {
|
_restoreFocus() {
|
||||||
// We only are allowed to move focus if we (still) 'own' it.
|
// We only are allowed to move focus if we (still) 'own' it.
|
||||||
|
|
@ -893,19 +926,20 @@ export class OverlayController extends EventTargetShim {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up backdrop on the given overlay. If there was a backdrop on another element
|
* 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.
|
* animation is played.
|
||||||
* @param {{ animation?: boolean, phase: OverlayPhase }} config
|
* @param {{ animation?: boolean, phase: OverlayPhase }} config
|
||||||
*/
|
*/
|
||||||
_handleBackdrop({ animation = true, phase }) {
|
_handleBackdrop({ phase }) {
|
||||||
switch (phase) {
|
switch (phase) {
|
||||||
case 'init': {
|
case 'init': {
|
||||||
if (!this.backdropNode) {
|
if (!this.backdropNode) {
|
||||||
this.__backdropNode = document.createElement('div');
|
this.__backdropNode = document.createElement('div');
|
||||||
/** @type {HTMLElement} */
|
/** @type {HTMLElement} */
|
||||||
|
(this.backdropNode).slot = 'backdrop';
|
||||||
|
/** @type {HTMLElement} */
|
||||||
(this.backdropNode).classList.add(`${this.placementMode}-overlays__backdrop`);
|
(this.backdropNode).classList.add(`${this.placementMode}-overlays__backdrop`);
|
||||||
}
|
}
|
||||||
this.backdropNode.slot = '_overlay-shadow-outlet';
|
|
||||||
|
|
||||||
let insertionAnchor = /** @type {HTMLElement} */ (this.contentNode.parentNode);
|
let insertionAnchor = /** @type {HTMLElement} */ (this.contentNode.parentNode);
|
||||||
let insertionBefore = this.contentNode;
|
let insertionBefore = this.contentNode;
|
||||||
|
|
@ -917,12 +951,7 @@ export class OverlayController extends EventTargetShim {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'show':
|
case 'show':
|
||||||
if (this.placementMode === 'global') {
|
this.backdropNode.classList.add(`${this.placementMode}-overlays__backdrop--visible`);
|
||||||
this.backdropNode.classList.add('global-overlays__backdrop--visible');
|
|
||||||
if (animation === true) {
|
|
||||||
this.backdropNode.classList.add('global-overlays__backdrop--fade-in');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.__hasActiveBackdrop = true;
|
this.__hasActiveBackdrop = true;
|
||||||
break;
|
break;
|
||||||
case 'hide':
|
case 'hide':
|
||||||
|
|
@ -930,39 +959,15 @@ export class OverlayController extends EventTargetShim {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.__hasActiveBackdrop = false;
|
this.__hasActiveBackdrop = false;
|
||||||
|
|
||||||
if (this.placementMode === 'global') {
|
|
||||||
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 = () => {
|
|
||||||
if (this.backdropNode) {
|
|
||||||
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');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'teardown':
|
case 'teardown':
|
||||||
if (!this.backdropNode || !this.backdropNode.parentNode) {
|
if (!this.backdropNode || !this.backdropNode.parentNode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (animation && this.__backDropAnimation) {
|
if (this.__backdropAnimation) {
|
||||||
this.__backdropNodeToBeTornDown = this.backdropNode;
|
this.__backdropNodeToBeTornDown = this.backdropNode;
|
||||||
|
|
||||||
this.__backDropAnimation.then(() => {
|
this.__backdropAnimation.then(() => {
|
||||||
if (this.__backdropNodeToBeTornDown) {
|
if (this.__backdropNodeToBeTornDown) {
|
||||||
/** @type {HTMLElement} */ (this.__backdropNodeToBeTornDown.parentNode).removeChild(
|
/** @type {HTMLElement} */ (this.__backdropNodeToBeTornDown.parentNode).removeChild(
|
||||||
this.__backdropNodeToBeTornDown,
|
this.__backdropNodeToBeTornDown,
|
||||||
|
|
|
||||||
|
|
@ -85,11 +85,11 @@ export const globalOverlaysStyle = css`
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.global-overlays .global-overlays__backdrop--fade-in {
|
.global-overlays .global-overlays__backdrop--animation-in {
|
||||||
animation: global-overlays-backdrop-fade-in 300ms;
|
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;
|
animation: global-overlays-backdrop-fade-out 300ms;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue