refactor(react/dialogs): allow modals in sub-components

This commit is contained in:
Elian Doran 2025-08-27 19:35:47 +03:00
parent 1e1c8cc4ff
commit 3627a7dc93
No known key found for this signature in database

View File

@ -1,9 +1,8 @@
import { useContext, useEffect, useRef, useMemo } from "preact/hooks"; import { useEffect, useRef, useMemo } from "preact/hooks";
import { t } from "../../services/i18n"; import { t } from "../../services/i18n";
import { ComponentChildren } from "preact"; import { ComponentChildren } from "preact";
import type { CSSProperties, RefObject } from "preact/compat"; import type { CSSProperties, RefObject } from "preact/compat";
import { openDialog } from "../../services/dialog"; import { openDialog } from "../../services/dialog";
import { ParentComponent } from "./react_utils";
import { Modal as BootstrapModal } from "bootstrap"; import { Modal as BootstrapModal } from "bootstrap";
import { memo } from "preact/compat"; import { memo } from "preact/compat";
import { useSyncedRef } from "./hooks"; import { useSyncedRef } from "./hooks";
@ -68,7 +67,6 @@ interface ModalProps {
export default function Modal({ children, className, size, title, header, footer, footerStyle, footerAlignment, onShown, onSubmit, helpPageId, minWidth, maxWidth, zIndex, scrollable, onHidden: onHidden, modalRef: externalModalRef, formRef, bodyStyle, show, stackable }: ModalProps) { export default function Modal({ children, className, size, title, header, footer, footerStyle, footerAlignment, onShown, onSubmit, helpPageId, minWidth, maxWidth, zIndex, scrollable, onHidden: onHidden, modalRef: externalModalRef, formRef, bodyStyle, show, stackable }: ModalProps) {
const modalRef = useSyncedRef<HTMLDivElement>(externalModalRef); const modalRef = useSyncedRef<HTMLDivElement>(externalModalRef);
const modalInstanceRef = useRef<BootstrapModal>(); const modalInstanceRef = useRef<BootstrapModal>();
const parentWidget = useContext(ParentComponent);
const elementToFocus = useRef<Element | null>(); const elementToFocus = useRef<Element | null>();
useEffect(() => { useEffect(() => {
@ -94,18 +92,15 @@ export default function Modal({ children, className, size, title, header, footer
}, [ onShown, onHidden ]); }, [ onShown, onHidden ]);
useEffect(() => { useEffect(() => {
if (!parentWidget) { if (show && modalRef.current) {
return;
}
if (show) {
elementToFocus.current = document.activeElement; elementToFocus.current = document.activeElement;
openDialog(parentWidget.$widget, !stackable).then(($widget) => { openDialog($(modalRef.current), !stackable).then(($widget) => {
modalInstanceRef.current = BootstrapModal.getOrCreateInstance($widget[0]); modalInstanceRef.current = BootstrapModal.getOrCreateInstance($widget[0]);
}) })
} else { } else {
modalInstanceRef.current?.hide(); modalInstanceRef.current?.hide();
} }
}, [ show ]); }, [ show, modalRef.current ]);
// Memoize styles to prevent recreation on every render // Memoize styles to prevent recreation on every render
const dialogStyle = useMemo<CSSProperties>(() => { const dialogStyle = useMemo<CSSProperties>(() => {