fix(mui): lock <html> scroll for dialogs + freeze Modal title/labels during close
Scroll: MUI only locks <body>, but base.css 'html{overflow-x:hidden}' makes <html> the vertical scroller (overflow-x:hidden forces overflow-y:auto), so the page scrolled behind modals. Added a ref-counted useDialogScrollLock that locks <html> (with scrollbar-width padding) + disableScrollLock on the kit dialogs. Labels: Modal now freezes title/subtitle/submitText while closing (derive-state-from-props), so editing then saving no longer briefly flashes the 'create' title/button during the fade-out.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
import type { ReactNode } from "react";
|
||||
import { useState, type ReactNode } from "react";
|
||||
import Dialog from "@mui/material/Dialog";
|
||||
import DialogTitle from "@mui/material/DialogTitle";
|
||||
import DialogContent from "@mui/material/DialogContent";
|
||||
import DialogActions from "@mui/material/DialogActions";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import MuiButton from "@mui/material/Button";
|
||||
import useDialogScrollLock from "./useDialogScrollLock";
|
||||
|
||||
export interface ModalProps {
|
||||
isOpen: boolean;
|
||||
@@ -34,19 +35,34 @@ export default function Modal({
|
||||
cancelText = "Zrušit",
|
||||
maxWidth = "sm",
|
||||
}: ModalProps) {
|
||||
useDialogScrollLock(isOpen);
|
||||
// Freeze the shown title/subtitle/submitText while closing, so the fade-out
|
||||
// never flashes the "create" variant when the caller clears `editingUser` on
|
||||
// close (React derive-state-from-props: update only while open).
|
||||
const [shown, setShown] = useState({ title, subtitle, submitText });
|
||||
if (
|
||||
isOpen &&
|
||||
(shown.title !== title ||
|
||||
shown.subtitle !== subtitle ||
|
||||
shown.submitText !== submitText)
|
||||
) {
|
||||
setShown({ title, subtitle, submitText });
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={isOpen}
|
||||
onClose={loading ? undefined : onClose}
|
||||
fullWidth
|
||||
maxWidth={maxWidth}
|
||||
disableScrollLock
|
||||
slotProps={{ paper: { sx: { borderRadius: 3 } } }}
|
||||
>
|
||||
<DialogTitle sx={{ pb: subtitle ? 0.5 : 1.5 }}>
|
||||
{title}
|
||||
{subtitle && (
|
||||
<DialogTitle sx={{ pb: shown.subtitle ? 0.5 : 1.5 }}>
|
||||
{shown.title}
|
||||
{shown.subtitle && (
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{subtitle}
|
||||
{shown.subtitle}
|
||||
</Typography>
|
||||
)}
|
||||
</DialogTitle>
|
||||
@@ -60,7 +76,7 @@ export default function Modal({
|
||||
variant="contained"
|
||||
disabled={loading || submitDisabled}
|
||||
>
|
||||
{loading ? "Ukládám…" : submitText}
|
||||
{loading ? "Ukládám…" : shown.submitText}
|
||||
</MuiButton>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
||||
Reference in New Issue
Block a user