From b05860b6d2ea17db29a338659def49dc31082346 Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 29 Aug 2023 01:30:30 +0800 Subject: Refactor dialog module. --- FrontEnd/src/components/dialog/DialogProvider.tsx | 95 +++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 FrontEnd/src/components/dialog/DialogProvider.tsx (limited to 'FrontEnd/src/components/dialog/DialogProvider.tsx') diff --git a/FrontEnd/src/components/dialog/DialogProvider.tsx b/FrontEnd/src/components/dialog/DialogProvider.tsx new file mode 100644 index 00000000..bb85e4cf --- /dev/null +++ b/FrontEnd/src/components/dialog/DialogProvider.tsx @@ -0,0 +1,95 @@ +import { useState, useContext, createContext, ReactNode } from "react"; + +import { UiLogicError } from "../common"; + +type DialogMap = { + [K in D]: ReactNode; +}; + +interface DialogController { + currentDialog: D | null; + currentDialogReactNode: ReactNode; + canSwitchDialog: boolean; + switchDialog: (newDialog: D | null) => void; + setCanSwitchDialog: (enable: boolean) => void; + closeDialog: () => void; + forceSwitchDialog: (newDialog: D | null) => void; + forceCloseDialog: () => void; +} + +export function useDialog( + dialogs: DialogMap, + options?: { + initDialog?: D | null; + onClose?: { + [K in D]?: () => void; + }; + }, +): { + controller: DialogController; + switchDialog: (newDialog: D | null) => void; + forceSwitchDialog: (newDialog: D | null) => void; + createDialogSwitch: (newDialog: D | null) => () => void; +} { + const [canSwitchDialog, setCanSwitchDialog] = useState(true); + const [dialog, setDialog] = useState(options?.initDialog ?? null); + + const forceSwitchDialog = (newDialog: D | null) => { + if (dialog != null) { + options?.onClose?.[dialog]?.(); + } + setDialog(newDialog); + setCanSwitchDialog(true); + }; + + const switchDialog = (newDialog: D | null) => { + if (canSwitchDialog) { + forceSwitchDialog(newDialog); + } + }; + + const controller: DialogController = { + currentDialog: dialog, + currentDialogReactNode: dialog == null ? null : dialogs[dialog], + canSwitchDialog, + switchDialog, + setCanSwitchDialog, + closeDialog: () => switchDialog(null), + forceSwitchDialog, + forceCloseDialog: () => forceSwitchDialog(null), + }; + + return { + controller, + switchDialog, + forceSwitchDialog, + createDialogSwitch: (newDialog: D | null) => () => switchDialog(newDialog), + }; +} + +const DialogControllerContext = createContext | null>( + null, +); + +export function useDialogController(): DialogController { + const controller = useContext(DialogControllerContext); + if (controller == null) throw new UiLogicError("not in dialog provider"); + return controller; +} + +export function useCloseDialog(): () => void { + const controller = useDialogController(); + return controller.closeDialog; +} + +export function DialogProvider({ + controller, +}: { + controller: DialogController; +}) { + return ( + + {controller.currentDialogReactNode} + + ); +} -- cgit v1.2.3