From 88d9687575dbd7f31f279faf5bbfe4f92521d885 Mon Sep 17 00:00:00 2001 From: Zack Rauen Date: Tue, 11 Apr 2023 18:30:36 -0400 Subject: [PATCH] Use custom stack --- renderer/src/ui/modals.js | 28 +++++++++-- renderer/src/ui/modals/backdrop.jsx | 33 +++++++++++++ renderer/src/ui/modals/root.jsx | 48 ++++++++++++++++++- renderer/src/ui/modals/stack.jsx | 73 +++++++++++++++++++++++++++++ 4 files changed, 177 insertions(+), 5 deletions(-) create mode 100644 renderer/src/ui/modals/backdrop.jsx create mode 100644 renderer/src/ui/modals/stack.jsx 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