diff --git a/renderer/src/ui/modals.js b/renderer/src/ui/modals.js
index 0e094b0f..b938f80c 100644
--- a/renderer/src/ui/modals.js
+++ b/renderer/src/ui/modals.js
@@ -1,6 +1,6 @@
import {Config} from "data";
import Logger from "common/logger";
-import {WebpackModules, React, ReactDOM, Settings, Strings, DOMManager} from "modules";
+import {WebpackModules, React, ReactDOM, Settings, Strings, DOMManager, Events} from "modules";
import FormattableString from "../structs/string";
import AddonErrorModal from "./modals/addonerrormodal";
import ErrorBoundary from "./errorboundary";
@@ -14,6 +14,7 @@ import ConfirmationModal from "./modals/confirmation";
import Button from "./base/button";
import CustomMarkdown from "./base/markdown";
import ChangelogModal from "./modals/changelog";
+import ModalStack, {generateKey} from "./modals/stack";
export default class Modals {
@@ -172,7 +173,7 @@ export default class Modals {
if (!Array.isArray(content)) content = [content];
content = content.map(c => typeof(c) === "string" ? React.createElement(CustomMarkdown, null, c) : c);
- const modalKey = ModalActions.openModal(props => {
+ const modalKey = this.openModal(props => {
return React.createElement(ErrorBoundary, {
onError: () => {
setTimeout(() => {
@@ -204,7 +205,7 @@ export default class Modals {
pluginErrors: Array.isArray(pluginErrors) ? pluginErrors : [],
themeErrors: Array.isArray(themeErrors) ? themeErrors : []
};
- this.ModalActions.openModal(props => {
+ this.openModal(props => {
return React.createElement(ErrorBoundary, null, React.createElement(AddonErrorModal, Object.assign(options, props)));
});
}
@@ -212,7 +213,7 @@ export default class Modals {
static showChangelogModal(options = {}) {
options = Object.assign({image: "https://i.imgur.com/wuh5yMK.png", description: "", changes: [], title: "BetterDiscord", subtitle: `v${Config.version}`}, options);
- const key = this.ModalActions.openModal(props => {
+ const key = this.openModal(props => {
return React.createElement(ErrorBoundary, null, React.createElement(ChangelogModal, Object.assign(options, props)));
});
return key;
@@ -263,4 +264,23 @@ export default class Modals {
return React.createElement(ErrorBoundary, null, React.createElement(ConfirmationModal, Object.assign(options, props), child));
});
}
+
+
+
+ static makeStack() {
+ const div = DOMManager.parseHTML(`
`);
+ DOMManager.bdBody.append(div);
+ ReactDOM.render(, div);
+ this.hasInitialized = true;
+ }
+
+ static openModal(render, options = {}) {
+ if (!this.hasInitialized) this.makeStack();
+ options.modalKey = generateKey(options.modalKey);
+ Events.emit("open-modal", render, options);
+ return options.modalKey;
+ }
}
+
+
+Modals.makeStack();
\ No newline at end of file
diff --git a/renderer/src/ui/modals/backdrop.jsx b/renderer/src/ui/modals/backdrop.jsx
new file mode 100644
index 00000000..066a7e41
--- /dev/null
+++ b/renderer/src/ui/modals/backdrop.jsx
@@ -0,0 +1,33 @@
+import {React, Utilities, WebpackModules} from "modules";
+
+const Spring = WebpackModules.getByProps("useSpring", "animated");
+
+
+export default function Backdrop({isVisible, className, onClick}) {
+ const transition = Spring.useTransition(isVisible, {
+ keys: e => e ? "backdrop" : "empty",
+ config: {duration: 300},
+ from: {
+ opacity: 0,
+ background: "var(--black-500)"
+ },
+ enter: {
+ opacity: 0.85,
+ background: "var(--black-500)"
+ },
+ leave: {
+ opacity: 0,
+ background: "var(--black-500)"
+ }
+ });
+
+ return transition((styles, visible) => {
+ if (!visible) return null;
+
+ return ;
+ });
+}
\ No newline at end of file
diff --git a/renderer/src/ui/modals/root.jsx b/renderer/src/ui/modals/root.jsx
index ff5b7a93..ad74eedb 100644
--- a/renderer/src/ui/modals/root.jsx
+++ b/renderer/src/ui/modals/root.jsx
@@ -18,7 +18,8 @@ export const Styles = Object.freeze({
export default function ModalRoot({className, transitionState, children, size = Sizes.DYNAMIC, style = Styles.CUSTOM}) {
- const visible = transitionState == 0 || transitionState == 1;
+ const visible = transitionState == 0 || transitionState == 1; // 300 ms
+ // const visible = transitionState;
const springStyles = Spring.useSpring({
opacity: visible ? 1 : 0,
transform: visible ? "scale(1)" : "scale(0.7)",
@@ -28,12 +29,57 @@ export default function ModalRoot({className, transitionState, children, size =
clamp: true
}
});
+
return
{children}
;
+ // const [visible, setVisible] = React.useState(true);
+
+ // const visible = transitionState < 2;
+ // const springTransition = Spring.useTransition(transitionState, {
+ // keys: e => e ? "backdrop" : "empty",
+ // from: {
+ // opacity: 0,
+ // transform: "scale(0.7)"
+ // },
+ // enter: {
+ // opacity: 1,
+ // transform: "scale(1)"
+ // },
+ // leave: {
+ // opacity: 0,
+ // transform: "scale(0.7)"
+ // },
+ // // config: (a, b, c, d) => {
+ // // console.log({a, b, c, d});
+ // // return {
+ // // duration: a ? 300 : 100,
+ // // easing: a ? Anims.Easing.inOut(Anims.Easing.back()) : Anims.Easing.quad,
+ // // clamp: true
+ // // };
+ // // }
+ // config: (a, b, c) => {
+ // console.log({a, b, c});
+ // return {
+ // duration: true ? 300 : 100,
+ // easing: true ? Anims.Easing.inOut(Anims.Easing.back()) : Anims.Easing.quad,
+ // clamp: true
+ // };
+ // }
+ // });
+
+ // return springTransition((styles, isVisible) => {
+ // if (!isVisible) console.log("not visible");
+ // return
+ // {children}
+ // ;
+ // });
}
ModalRoot.Sizes = Sizes;
diff --git a/renderer/src/ui/modals/stack.jsx b/renderer/src/ui/modals/stack.jsx
new file mode 100644
index 00000000..37bcc857
--- /dev/null
+++ b/renderer/src/ui/modals/stack.jsx
@@ -0,0 +1,73 @@
+import {React, Events, WebpackModules} from "modules";
+import Backdrop from "./backdrop";
+
+const {Fragment, useState, useCallback, useEffect} = React;
+
+
+const Transitions = WebpackModules.getModule(m => m?.defaultProps?.transitionAppear);
+// const Transitions = WebpackModules.getByProps("TransitionGroup").TransitionGroup;
+
+class ModalLayer extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {transitionState: null};
+ }
+
+ componentWillEnter(finish) {
+ this.setState({transitionState: 0});
+ setTimeout(() => {
+ this.setState({transitionState: 1});
+ finish();
+ }, 300);
+
+ }
+ componentWillLeave(finish) {
+ this.setState({transitionState: 2});
+ setTimeout(() => {
+ this.setState({transitionState: 3});
+ finish();
+ }, 300);
+ }
+
+ render() {
+ return React.createElement("div", {className: "bd-modal-layer"}, this.props.render({
+ transitionState: this.state.transitionState,
+ onClose: this.props.onClose
+ }));
+ }
+}
+
+// ENTERING 0
+// ENTERED 1
+// EXITING 2
+// EXITED 3
+// HIDDEN 4
+
+let modalKey = 0;
+export const generateKey = key => key ? `${key}-${modalKey++}` : modalKey++;
+
+export default function ModalStack() {
+ const [modals, setModals] = useState([]);
+
+ const addModal = useCallback((render, props = {}) => {
+ setModals(m => [...m, {...props, render}]);
+ }, []);
+ const removeModal = useCallback((key) => {
+ setModals(mods => mods.filter(m => {
+ if (m.modalKey === key && m.onClose) m.onClose();
+ return m.modalKey !== key;
+ }));
+ }, []);
+
+ useEffect(() => {
+ Events.on("open-modal", addModal);
+ return () => {
+ Events.off("open-modal", addModal);
+ };
+ }, [addModal]);
+
+ return
+ removeModal(modals[modals.length - 1].modalKey)} />
+ {modals.length && removeModal(modals[modals.length - 1].modalKey)} />}
+ ;
+}
\ No newline at end of file