mirror of
https://github.com/revoltchat/revite.git
synced 2024-12-25 23:22:06 -05:00
Modals: Add close animation.
This commit is contained in:
parent
41567413f2
commit
98ea3e7af7
5 changed files with 43 additions and 6 deletions
2
external/lang
vendored
2
external/lang
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit e91ad23b9747d424e14566e858b21d59a61d0ee0
|
Subproject commit f28b9849a1765c45c67b173516f1776113828233
|
|
@ -1,9 +1,10 @@
|
||||||
import styled, { css, keyframes } from "styled-components";
|
import styled, { css, keyframes } from "styled-components";
|
||||||
|
|
||||||
import { createPortal, useEffect } from "preact/compat";
|
import { createPortal, useEffect, useState } from "preact/compat";
|
||||||
|
|
||||||
import { Children } from "../../types/Preact";
|
import { Children } from "../../types/Preact";
|
||||||
import Button, { ButtonProps } from "./Button";
|
import Button, { ButtonProps } from "./Button";
|
||||||
|
import { internalSubscribe } from "../../lib/eventEmitter";
|
||||||
|
|
||||||
const open = keyframes`
|
const open = keyframes`
|
||||||
0% {opacity: 0;}
|
0% {opacity: 0;}
|
||||||
|
@ -11,12 +12,23 @@ const open = keyframes`
|
||||||
100% {opacity: 1;}
|
100% {opacity: 1;}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const close = keyframes`
|
||||||
|
0% {opacity: 1;}
|
||||||
|
70% {opacity: 0;}
|
||||||
|
100% {opacity: 0;}
|
||||||
|
`;
|
||||||
|
|
||||||
const zoomIn = keyframes`
|
const zoomIn = keyframes`
|
||||||
0% {transform: scale(0.5);}
|
0% {transform: scale(0.5);}
|
||||||
98% {transform: scale(1.01);}
|
98% {transform: scale(1.01);}
|
||||||
100% {transform: scale(1);}
|
100% {transform: scale(1);}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const zoomOut = keyframes`
|
||||||
|
0% {transform: scale(1);}
|
||||||
|
100% {transform: scale(0.5);}
|
||||||
|
`;
|
||||||
|
|
||||||
const ModalBase = styled.div`
|
const ModalBase = styled.div`
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
@ -36,6 +48,14 @@ const ModalBase = styled.div`
|
||||||
|
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
background: rgba(0, 0, 0, 0.8);
|
background: rgba(0, 0, 0, 0.8);
|
||||||
|
|
||||||
|
&.closing {
|
||||||
|
animation-name: ${close};
|
||||||
|
}
|
||||||
|
|
||||||
|
&.closing > div {
|
||||||
|
animation-name: ${zoomOut};
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ModalContainer = styled.div`
|
const ModalContainer = styled.div`
|
||||||
|
@ -120,6 +140,8 @@ interface Props {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export let isModalClosing = false;
|
||||||
|
|
||||||
export default function Modal(props: Props) {
|
export default function Modal(props: Props) {
|
||||||
if (!props.visible) return null;
|
if (!props.visible) return null;
|
||||||
|
|
||||||
|
@ -138,12 +160,21 @@ export default function Modal(props: Props) {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const [animateClose, setAnimateClose] = useState(false);
|
||||||
|
isModalClosing = animateClose;
|
||||||
|
function onClose() {
|
||||||
|
setAnimateClose(true);
|
||||||
|
setTimeout(() => props.onClose(), 2e2);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => internalSubscribe('Modal', 'close', onClose), []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (props.disallowClosing) return;
|
if (props.disallowClosing) return;
|
||||||
|
|
||||||
function keyDown(e: KeyboardEvent) {
|
function keyDown(e: KeyboardEvent) {
|
||||||
if (e.key === "Escape") {
|
if (e.key === "Escape") {
|
||||||
props.onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,6 +185,7 @@ export default function Modal(props: Props) {
|
||||||
let confirmationAction = props.actions?.find(
|
let confirmationAction = props.actions?.find(
|
||||||
(action) => action.confirmation,
|
(action) => action.confirmation,
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!confirmationAction) return;
|
if (!confirmationAction) return;
|
||||||
|
|
||||||
|
@ -171,7 +203,7 @@ export default function Modal(props: Props) {
|
||||||
}, [confirmationAction]);
|
}, [confirmationAction]);
|
||||||
|
|
||||||
return createPortal(
|
return createPortal(
|
||||||
<ModalBase
|
<ModalBase className={animateClose ? 'closing' : undefined}
|
||||||
onClick={(!props.disallowClosing && props.onClose) || undefined}>
|
onClick={(!props.disallowClosing && props.onClose) || undefined}>
|
||||||
<ModalContainer onClick={(e) => (e.cancelBubble = true)}>
|
<ModalContainer onClick={(e) => (e.cancelBubble = true)}>
|
||||||
{content}
|
{content}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { isModalClosing } from "../../components/ui/Modal";
|
||||||
|
import { internalEmit } from "../../lib/eventEmitter";
|
||||||
import { Screen } from "./Intermediate";
|
import { Screen } from "./Intermediate";
|
||||||
import { ClipboardModal } from "./modals/Clipboard";
|
import { ClipboardModal } from "./modals/Clipboard";
|
||||||
import { ErrorModal } from "./modals/Error";
|
import { ErrorModal } from "./modals/Error";
|
||||||
|
@ -12,7 +14,7 @@ export interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Modals({ screen, openScreen }: Props) {
|
export default function Modals({ screen, openScreen }: Props) {
|
||||||
const onClose = () => openScreen({ id: "none" });
|
const onClose = () => isModalClosing ? openScreen({ id: "none" }) : internalEmit('Modal', 'close');
|
||||||
|
|
||||||
switch (screen.id) {
|
switch (screen.id) {
|
||||||
case "_prompt":
|
case "_prompt":
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import { useContext } from "preact/hooks";
|
import { useContext } from "preact/hooks";
|
||||||
|
import { isModalClosing } from "../../components/ui/Modal";
|
||||||
|
import { internalEmit } from "../../lib/eventEmitter";
|
||||||
|
|
||||||
import { IntermediateContext, useIntermediate } from "./Intermediate";
|
import { IntermediateContext, useIntermediate } from "./Intermediate";
|
||||||
import { SpecialInputModal } from "./modals/Input";
|
import { SpecialInputModal } from "./modals/Input";
|
||||||
|
@ -14,7 +16,7 @@ export default function Popovers() {
|
||||||
const { screen } = useContext(IntermediateContext);
|
const { screen } = useContext(IntermediateContext);
|
||||||
const { openScreen } = useIntermediate();
|
const { openScreen } = useIntermediate();
|
||||||
|
|
||||||
const onClose = () => openScreen({ id: "none" });
|
const onClose = () => isModalClosing ? openScreen({ id: "none" }) : internalEmit('Modal', 'close');
|
||||||
|
|
||||||
switch (screen.id) {
|
switch (screen.id) {
|
||||||
case "profile":
|
case "profile":
|
||||||
|
|
|
@ -26,4 +26,5 @@ export function internalEmit(ns: string, event: string, ...args: any[]) {
|
||||||
// - MessageBox/append
|
// - MessageBox/append
|
||||||
// - TextArea/focus
|
// - TextArea/focus
|
||||||
// - ReplyBar/add
|
// - ReplyBar/add
|
||||||
|
// - Modal/close
|
||||||
// - PWA/update
|
// - PWA/update
|
||||||
|
|
Loading…
Reference in a new issue