fix: modal transition not working (#433)
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user