fix: modal transition not working (#433)

This commit is contained in:
Meier Lukas
2024-05-04 20:58:44 +02:00
committed by GitHub
parent 5abd438a49
commit b888fad1fc
2 changed files with 57 additions and 30 deletions

View File

@@ -5,8 +5,10 @@ import {
createContext, createContext,
useCallback, useCallback,
useContext, useContext,
useEffect,
useReducer, useReducer,
useRef, useRef,
useState,
} from "react"; } from "react";
import { getDefaultZIndex, Modal } from "@mantine/core"; import { getDefaultZIndex, Modal } from "@mantine/core";
import { randomId } from "@mantine/hooks"; import { randomId } from "@mantine/hooks";
@@ -17,6 +19,7 @@ import { useI18n } from "@homarr/translation/client";
import type { ConfirmModalProps } from "./confirm-modal"; import type { ConfirmModalProps } from "./confirm-modal";
import { ConfirmModal } from "./confirm-modal"; import { ConfirmModal } from "./confirm-modal";
import type { ModalsState, ModalStateWithReference } from "./reducer";
import { modalReducer } from "./reducer"; import { modalReducer } from "./reducer";
import type { inferInnerProps, ModalDefinition } from "./type"; import type { inferInnerProps, ModalDefinition } from "./type";
@@ -32,7 +35,6 @@ interface ModalContextProps {
export const ModalContext = createContext<ModalContextProps | null>(null); export const ModalContext = createContext<ModalContextProps | null>(null);
export const ModalProvider = ({ children }: PropsWithChildren) => { export const ModalProvider = ({ children }: PropsWithChildren) => {
const t = useI18n();
const [state, dispatch] = useReducer(modalReducer, { const [state, dispatch] = useReducer(modalReducer, {
modals: [], modals: [],
current: null, current: null,
@@ -80,39 +82,64 @@ export const ModalProvider = ({ children }: PropsWithChildren) => {
return ( return (
<ModalContext.Provider value={{ openModalInner, closeModal }}> <ModalContext.Provider value={{ openModalInner, closeModal }}>
{activeModals.map((modal) => { {activeModals.map((modal) => (
const { defaultTitle: _ignored, ...otherModalProps } = <ActiveModal
modal.reference.modalProps; key={modal.id}
return ( modal={modal}
<Modal state={state}
key={modal.id} handleCloseModal={handleCloseModal}
zIndex={getDefaultZIndex("modal") + 1} />
display={modal.id === state.current?.id ? undefined : "none"} ))}
style={{
userSelect: modal.id === state.current?.id ? undefined : "none",
}}
styles={{
title: {
fontSize: "1.25rem",
fontWeight: 500,
},
}}
trapFocus={modal.id === state.current?.id}
{...otherModalProps}
title={translateIfNecessary(t, modal.props.defaultTitle)}
opened={state.modals.length > 0}
onClose={handleCloseModal}
>
{modal.reference.content}
</Modal>
);
})}
{children} {children}
</ModalContext.Provider> </ModalContext.Provider>
); );
}; };
interface ActiveModalProps {
modal: ModalStateWithReference;
state: ModalsState;
handleCloseModal: () => void;
}
const ActiveModal = ({ modal, state, handleCloseModal }: ActiveModalProps) => {
const t = useI18n();
// The below code is used to animate the modal when it opens (using the transition)
// It is necessary as transition is not working when the modal is directly mounted and run
const [opened, setOpened] = useState(false);
useEffect(() => {
setTimeout(() => setOpened(true), 0);
}, []);
const { defaultTitle: _ignored, ...otherModalProps } =
modal.reference.modalProps;
return (
<Modal
key={modal.id}
zIndex={getDefaultZIndex("modal") + 1}
display={modal.id === state.current?.id ? undefined : "none"}
style={{
userSelect: modal.id === state.current?.id ? undefined : "none",
}}
styles={{
title: {
fontSize: "1.25rem",
fontWeight: 500,
},
}}
trapFocus={modal.id === state.current?.id}
{...otherModalProps}
title={translateIfNecessary(t, modal.props.defaultTitle)}
opened={opened}
onClose={handleCloseModal}
>
{modal.reference.content}
</Modal>
);
};
interface OpenModalOptions { interface OpenModalOptions {
keepMounted?: boolean; keepMounted?: boolean;
title?: stringOrTranslation; title?: stringOrTranslation;

View File

@@ -5,7 +5,7 @@ import { useContext } from "react";
import { ModalContext } from "."; import { ModalContext } from ".";
import type { ModalDefinition, ModalState } from "./type"; import type { ModalDefinition, ModalState } from "./type";
type ModalStateWithReference = ModalState & { export type ModalStateWithReference = ModalState & {
/** /**
* Reference to modal component instance * Reference to modal component instance
* Used so the modal can be persisted between navigating in newer modals * Used so the modal can be persisted between navigating in newer modals
@@ -13,7 +13,7 @@ type ModalStateWithReference = ModalState & {
reference: ReturnType<typeof getModal>; reference: ReturnType<typeof getModal>;
}; };
interface ModalsState { export interface ModalsState {
modals: ModalStateWithReference[]; modals: ModalStateWithReference[];
/** /**