Skip to content

Commit dc5b15c

Browse files
committed
Switch to Web Animations API
1 parent eea1802 commit dc5b15c

File tree

2 files changed

+35
-49
lines changed

2 files changed

+35
-49
lines changed

src/client/lazy-app/Modal/index.tsx

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as style from './style.css';
33
import 'add-css:./style.css';
44
import { linkRef } from 'shared/prerendered-app/util';
55
import { cleanSet } from '../util/clean-modify';
6+
import { animateTo } from '../util';
67

78
interface Props {
89
icon: VNode;
@@ -19,12 +20,8 @@ export default class Modal extends Component<Props, State> {
1920

2021
componentDidMount() {
2122
if (!this.dialogElement) throw new Error('Modal missing');
22-
// Once a transition ends, check if the modal should be closed (not just hidden)
23-
// dialog.close() instantly hides the modal, so we call it AFTER fading it out i.e. on transition end
24-
this.dialogElement.addEventListener('transitionend', (event) => {
25-
event.stopPropagation();
26-
this._closeOnTransitionEnd();
27-
});
23+
24+
// Set inert by default
2825
this.dialogElement.inert = true;
2926

3027
// Prevent events from leaking through the dialog
@@ -36,16 +33,10 @@ export default class Modal extends Component<Props, State> {
3633

3734
private _closeOnTransitionEnd = () => {
3835
// If modal does not exist
39-
// Or if it's not being closed at the moment
40-
if (
41-
!this.dialogElement ||
42-
!this.dialogElement.classList.contains(style.modalClosing)
43-
)
44-
return;
36+
if (!this.dialogElement) return;
4537

4638
this.dialogElement.close();
47-
this.dialogElement.classList.remove(style.modalClosing);
48-
this.dialogElement.setAttribute('inert', 'enabled');
39+
this.dialogElement.inert = true;
4940
this.setState({ shown: false });
5041
};
5142

@@ -55,15 +46,41 @@ export default class Modal extends Component<Props, State> {
5546

5647
this.dialogElement.inert = false;
5748
this.dialogElement.showModal();
49+
// animate modal opening
50+
animateTo(
51+
this.dialogElement,
52+
[
53+
{ opacity: 0, transform: 'translateY(50px)' },
54+
{ opacity: 1, transform: 'translateY(0px)' },
55+
],
56+
{ duration: 250, easing: 'ease' },
57+
);
58+
// animate modal::backdrop
59+
animateTo(this.dialogElement, [{ opacity: 0 }, { opacity: 1 }], {
60+
duration: 250,
61+
easing: 'linear',
62+
pseudoElement: '::backdrop',
63+
});
5864
this.setState({ shown: true });
5965
}
6066

6167
private _hideModal() {
6268
if (!this.dialogElement || !this.dialogElement.open)
6369
throw Error('Modal missing / hidden');
6470

65-
// Make the modal fade out
66-
this.dialogElement.classList.add(style.modalClosing);
71+
// animate modal closing
72+
const anim = animateTo(
73+
this.dialogElement,
74+
{ opacity: 0, transform: 'translateY(50px)' },
75+
{ duration: 250, easing: 'ease' },
76+
);
77+
// animate modal::backdrop
78+
animateTo(this.dialogElement, [{ opacity: 0 }], {
79+
duration: 250,
80+
easing: 'linear',
81+
pseudoElement: '::backdrop',
82+
});
83+
anim.onfinish = this._closeOnTransitionEnd;
6784
}
6885

6986
private _onKeyDown(e: KeyboardEvent) {

src/client/lazy-app/Modal/style.css

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,45 +17,14 @@ dialog {
1717
border-radius: 10px;
1818
overflow: hidden;
1919

20-
background-color: var(--off-black);
21-
2220
opacity: 0;
23-
transform: translateY(50px);
24-
transition: 250ms ease;
21+
background-color: var(--off-black);
2522

26-
/* ::backdrop is created when dialog is opened, so animating it needs trickery */
23+
/* Note: dialog and ::backdrop are animated using the Animations API in the component file */
2724

2825
&::backdrop {
2926
background-color: rgba(0, 0, 0, 30%);
3027
}
31-
32-
&[open]::backdrop {
33-
animation: backdrop-fade-in 250ms linear;
34-
35-
@keyframes backdrop-fade-in {
36-
from {
37-
opacity: 0;
38-
}
39-
to {
40-
opacity: 1;
41-
}
42-
}
43-
}
44-
45-
&.modal--closing::backdrop {
46-
transition: opacity 250ms linear;
47-
opacity: 0;
48-
}
49-
}
50-
51-
dialog[open] {
52-
opacity: 1;
53-
transform: translateY(0px);
54-
}
55-
56-
dialog.modal--closing {
57-
opacity: 0;
58-
transform: translateY(50px);
5928
}
6029

6130
@media (max-width: 720px) {

0 commit comments

Comments
 (0)