fix(ui): lost animation effect when the drawer closes

This commit is contained in:
Fu Diwei
2025-08-13 20:51:15 +08:00
parent 6882b08ffa
commit f440103fce
17 changed files with 148 additions and 95 deletions
+6 -9
View File
@@ -58,7 +58,7 @@ const DrawerForm = <T extends NonNullable<unknown> = any>({
form: formInst,
formPending,
formProps,
submit,
submit: submitForm,
} = useAntdForm({
form,
onSubmit: (values) => {
@@ -75,25 +75,22 @@ const DrawerForm = <T extends NonNullable<unknown> = any>({
const mergedDrawerProps: DrawerProps = {
...drawerProps,
closeIcon: false,
afterOpenChange: (open) => {
if (!open && !mergedFormProps.preserve) {
formInst.resetFields();
}
drawerProps?.afterOpenChange?.(open);
},
onClose: async (e) => {
if (formPending) return;
// 关闭 Drawer 时 Promise.reject 阻止关闭
await drawerProps?.onClose?.(e);
setOpen(false);
if (!mergedFormProps.preserve) {
formInst.resetFields();
}
},
};
const handleOkClick = async () => {
// 提交表单返回 Promise.reject 时不关闭 Drawer
await submit();
await submitForm();
setOpen(false);
};
+32 -18
View File
@@ -1,4 +1,4 @@
import { useEffect, useRef, useState } from "react";
import { startTransition, useCallback, useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { IconX } from "@tabler/icons-react";
import { useControllableValue } from "ahooks";
@@ -12,6 +12,8 @@ import { getErrMsg } from "@/utils/error";
import AccessForm, { type AccessFormInstance, type AccessFormProps } from "./AccessForm";
export interface AccessEditDrawerProps {
afterClose?: () => void;
afterSubmit?: (record: AccessModel) => void;
data?: AccessFormProps["initialValues"];
loading?: boolean;
mode: AccessFormProps["mode"];
@@ -19,10 +21,9 @@ export interface AccessEditDrawerProps {
trigger?: React.ReactNode;
usage?: AccessFormProps["usage"];
onOpenChange?: (open: boolean) => void;
afterSubmit?: (record: AccessModel) => void;
}
const AccessEditDrawer = ({ mode, data, loading, trigger, usage, afterSubmit, ...props }: AccessEditDrawerProps) => {
const AccessEditDrawer = ({ afterClose, afterSubmit, mode, data, loading, trigger, usage, ...props }: AccessEditDrawerProps) => {
const { t } = useTranslation();
const { notification } = App.useApp();
@@ -99,7 +100,8 @@ const AccessEditDrawer = ({ mode, data, loading, trigger, usage, afterSubmit, ..
{triggerEl}
<Drawer
afterOpenChange={setOpen}
afterOpenChange={(open) => !open && afterClose?.()}
autoFocus
closeIcon={false}
destroyOnHidden
footer={
@@ -141,29 +143,41 @@ const AccessEditDrawer = ({ mode, data, loading, trigger, usage, afterSubmit, ..
);
};
const useProps = () => {
const [data, setData] = useState<AccessEditDrawerProps["data"]>();
const useDrawer = () => {
type DataType = AccessEditDrawerProps["data"];
const [data, setData] = useState<DataType>();
const [open, setOpen] = useState<boolean>(false);
const onOpenChange = (open: boolean) => {
const onOpenChange = useCallback((open: boolean) => {
setOpen(open);
if (!open) {
setData(void 0);
}
};
}, []);
return {
data,
open,
setData,
setOpen,
onOpenChange,
drawerProps: {
afterClose: () => {
startTransition(() => {
if (!open) {
setData(void 0);
}
});
},
data,
open,
onOpenChange,
},
open: (data: NonNullable<DataType>) => {
setData(data);
setOpen(true);
},
close: () => {
setOpen(false);
},
};
};
const _default = Object.assign(AccessEditDrawer, {
useProps,
useDrawer,
});
export default _default;
@@ -1,4 +1,4 @@
import { useState } from "react";
import { startTransition, useCallback, useState } from "react";
import { IconX } from "@tabler/icons-react";
import { useControllableValue } from "ahooks";
import { Button, Drawer, Flex } from "antd";
@@ -9,6 +9,7 @@ import { useTriggerElement } from "@/hooks";
import CertificateDetail from "./CertificateDetail";
export interface CertificateDetailDrawerProps {
afterClose?: () => void;
data?: CertificateModel;
loading?: boolean;
open?: boolean;
@@ -16,7 +17,7 @@ export interface CertificateDetailDrawerProps {
onOpenChange?: (open: boolean) => void;
}
const CertificateDetailDrawer = ({ data, loading, trigger, ...props }: CertificateDetailDrawerProps) => {
const CertificateDetailDrawer = ({ afterClose, data, loading, trigger, ...props }: CertificateDetailDrawerProps) => {
const [open, setOpen] = useControllableValue<boolean>(props, {
valuePropName: "open",
defaultValuePropName: "defaultOpen",
@@ -30,7 +31,8 @@ const CertificateDetailDrawer = ({ data, loading, trigger, ...props }: Certifica
{triggerEl}
<Drawer
afterOpenChange={setOpen}
afterOpenChange={(open) => !open && afterClose?.()}
autoFocus
closeIcon={false}
destroyOnHidden
open={open}
@@ -60,29 +62,41 @@ const CertificateDetailDrawer = ({ data, loading, trigger, ...props }: Certifica
);
};
const useProps = () => {
const [data, setData] = useState<CertificateDetailDrawerProps["data"]>();
const useDrawer = () => {
type DataType = CertificateDetailDrawerProps["data"];
const [data, setData] = useState<DataType>();
const [open, setOpen] = useState<boolean>(false);
const onOpenChange = (open: boolean) => {
const onOpenChange = useCallback((open: boolean) => {
setOpen(open);
if (!open) {
setData(void 0);
}
};
}, []);
return {
data,
open,
setData,
setOpen,
onOpenChange,
drawerProps: {
afterClose: () => {
startTransition(() => {
if (!open) {
setData(void 0);
}
});
},
data,
open,
onOpenChange,
},
open: (data: NonNullable<DataType>) => {
setData(data);
setOpen(true);
},
close: () => {
setOpen(false);
},
};
};
const _default = Object.assign(CertificateDetailDrawer, {
useProps,
useDrawer,
});
export default _default;
@@ -1,4 +1,4 @@
import { useState } from "react";
import { startTransition, useCallback, useState } from "react";
import { IconX } from "@tabler/icons-react";
import { useControllableValue } from "ahooks";
import { Button, Drawer, Flex } from "antd";
@@ -10,6 +10,7 @@ import { useTriggerElement } from "@/hooks";
import WorkflowRunDetail from "./WorkflowRunDetail";
export interface WorkflowRunDetailDrawerProps {
afterClose?: () => void;
data?: WorkflowRunModel;
loading?: boolean;
open?: boolean;
@@ -17,7 +18,7 @@ export interface WorkflowRunDetailDrawerProps {
onOpenChange?: (open: boolean) => void;
}
const WorkflowRunDetailDrawer = ({ data, loading, trigger, ...props }: WorkflowRunDetailDrawerProps) => {
const WorkflowRunDetailDrawer = ({ afterClose, data, loading, trigger, ...props }: WorkflowRunDetailDrawerProps) => {
const [open, setOpen] = useControllableValue<boolean>(props, {
valuePropName: "open",
defaultValuePropName: "defaultOpen",
@@ -31,7 +32,7 @@ const WorkflowRunDetailDrawer = ({ data, loading, trigger, ...props }: WorkflowR
{triggerEl}
<Drawer
afterOpenChange={setOpen}
afterOpenChange={(open) => !open && afterClose?.()}
closeIcon={false}
destroyOnHidden
open={open}
@@ -61,29 +62,41 @@ const WorkflowRunDetailDrawer = ({ data, loading, trigger, ...props }: WorkflowR
);
};
const useProps = () => {
const [data, setData] = useState<WorkflowRunDetailDrawerProps["data"]>();
const useDrawer = () => {
type DataType = WorkflowRunDetailDrawerProps["data"];
const [data, setData] = useState<DataType>();
const [open, setOpen] = useState<boolean>(false);
const onOpenChange = (open: boolean) => {
const onOpenChange = useCallback((open: boolean) => {
setOpen(open);
if (!open) {
setData(undefined);
}
};
}, []);
return {
data,
open,
setData,
setOpen,
onOpenChange,
drawerProps: {
afterClose: () => {
startTransition(() => {
if (!open) {
setData(void 0);
}
});
},
data,
open,
onOpenChange,
},
open: (data: NonNullable<DataType>) => {
setData(data);
setOpen(true);
},
close: () => {
setOpen(false);
},
};
};
const _default = Object.assign(WorkflowRunDetailDrawer, {
useProps,
useDrawer,
});
export default _default;
@@ -1,4 +1,4 @@
import { startTransition, useMemo, useState } from "react";
import { startTransition, useCallback, useMemo, useState } from "react";
import { type FlowNodeEntity } from "@flowgram.ai/fixed-layout-editor";
import { useControllableValue } from "ahooks";
@@ -14,6 +14,7 @@ import StartNodeConfigDrawer from "./forms/StartNodeConfigDrawer";
import { NodeType } from "./nodes/typings";
export interface NodeDrawerProps {
afterClose?: () => void;
children?: React.ReactNode;
loading?: boolean;
node?: FlowNodeEntity;
@@ -68,31 +69,41 @@ const NodeDrawer = ({ node, trigger, ...props }: NodeDrawerProps) => {
);
};
const useProps = () => {
const [node, setNode] = useState<NodeDrawerProps["node"]>();
const useDrawer = () => {
type NodeDataType = NodeDrawerProps["node"];
const [node, setNode] = useState<NodeDataType>();
const [open, setOpen] = useState<boolean>(false);
const onOpenChange = (open: boolean) => {
const onOpenChange = useCallback((open: boolean) => {
setOpen(open);
startTransition(() => {
if (!open) {
setNode(void 0);
}
});
};
}, []);
return {
node,
open,
setNode,
setOpen,
onOpenChange,
drawerProps: {
afterClose: () => {
startTransition(() => {
if (!open) {
setNode(void 0);
}
});
},
node,
open,
onOpenChange,
},
open: (node: NonNullable<NodeDataType>) => {
setNode(node);
setOpen(true);
},
close: () => {
setOpen(false);
},
};
};
const _default = Object.assign(NodeDrawer, {
useProps,
useDrawer,
});
export default _default;
@@ -7,6 +7,7 @@ import BizApplyNodeConfigForm from "./BizApplyNodeConfigForm";
import { NodeType } from "../nodes/typings";
export interface BizApplyNodeConfigDrawerProps {
afterClose?: () => void;
loading?: boolean;
node: FlowNodeEntity;
open?: boolean;
@@ -7,6 +7,7 @@ import BizDeployNodeConfigForm from "./BizDeployNodeConfigForm";
import { NodeType } from "../nodes/typings";
export interface BizDeployNodeConfigDrawerProps {
afterClose?: () => void;
loading?: boolean;
node: FlowNodeEntity;
open?: boolean;
@@ -7,6 +7,7 @@ import BizMonitorNodeConfigForm from "./BizMonitorNodeConfigForm";
import { NodeType } from "../nodes/typings";
export interface BizMonitorNodeConfigDrawerProps {
afterClose?: () => void;
loading?: boolean;
node: FlowNodeEntity;
open?: boolean;
@@ -7,6 +7,7 @@ import BizNotifyNodeConfigForm from "./BizNotifyNodeConfigForm";
import { NodeType } from "../nodes/typings";
export interface BizNotifyNodeConfigDrawerProps {
afterClose?: () => void;
loading?: boolean;
node: FlowNodeEntity;
open?: boolean;
@@ -7,6 +7,7 @@ import BizUploadNodeConfigForm from "./BizUploadNodeConfigForm";
import { NodeType } from "../nodes/typings";
export interface BizUploadNodeConfigDrawerProps {
afterClose?: () => void;
loading?: boolean;
node: FlowNodeEntity;
open?: boolean;
@@ -7,6 +7,7 @@ import BranchBlockNodeConfigForm from "./BranchBlockNodeConfigForm";
import { NodeType } from "../nodes/typings";
export interface BranchBlockNodeConfigDrawerProps {
afterClose?: () => void;
loading?: boolean;
node: FlowNodeEntity;
open?: boolean;
@@ -7,6 +7,7 @@ import StartNodeConfigForm from "./StartNodeConfigForm";
import { NodeType } from "../nodes/typings";
export interface StartNodeConfigDrawerProps {
afterClose?: () => void;
loading?: boolean;
node: FlowNodeEntity;
open?: boolean;
@@ -12,6 +12,7 @@ import { type NodeRegistry } from "../nodes/typings";
export interface NodeConfigDrawerProps {
children: React.ReactNode;
afterClose?: () => void;
anchor?: Pick<Required<AnchorProps>, "items"> | false;
footer?: boolean;
form: FormInstance;
@@ -21,7 +22,7 @@ export interface NodeConfigDrawerProps {
onOpenChange?: (open: boolean) => void;
}
export const NodeConfigDrawer = ({ children, anchor, footer = true, form: formInst, loading, node, ...props }: NodeConfigDrawerProps) => {
export const NodeConfigDrawer = ({ children, afterClose, anchor, footer = true, form: formInst, loading, node, ...props }: NodeConfigDrawerProps) => {
const { t } = useTranslation();
const { modal, notification } = App.useApp();
@@ -134,7 +135,8 @@ export const NodeConfigDrawer = ({ children, anchor, footer = true, form: formIn
paddingBottom: anchor ? 0 : void 0,
},
}}
afterOpenChange={setOpen}
afterOpenChange={(open) => !open && afterClose?.()}
autoFocus
closeIcon={false}
destroyOnHidden
footer={
+3 -5
View File
@@ -281,19 +281,17 @@ const AccessList = () => {
navigate(`/accesses/new?usage=${filters["usage"]}`);
};
const { setData: setDetailRecord, setOpen: setDetailOpen, ...detailDrawerProps } = AccessEditDrawer.useProps();
const { drawerProps: detailDrawerProps, ...detailDrawer } = AccessEditDrawer.useDrawer();
const [detailMode, setDetailMode] = useState<AccessEditDrawerProps["mode"]>("create");
const handleRecordDetailClick = (access: AccessModel) => {
setDetailRecord(access);
setDetailMode("edit");
setDetailOpen(true);
detailDrawer.open(access);
};
const handleRecordDuplicateClick = (access: AccessModel) => {
setDetailRecord({ ...access, id: void 0, name: `${access.name}-copy` });
setDetailMode("create");
setDetailOpen(true);
detailDrawer.open({ ...access, id: void 0, name: `${access.name}-copy` });
};
const handleRecordDeleteClick = async (access: AccessModel) => {
@@ -285,11 +285,10 @@ const CertificateList = () => {
setPageSize(pageSize);
};
const { setData: setDetailRecord, setOpen: setDetailOpen, ...detailDrawerProps } = CertificateDetailDrawer.useProps();
const { drawerProps: detailDrawerProps, ...detailDrawer } = CertificateDetailDrawer.useDrawer();
const handleRecordDetailClick = (certificate: CertificateModel) => {
setDetailRecord(certificate);
setDetailOpen(true);
detailDrawer.open(certificate);
};
const handleRecordDeleteClick = (certificate: CertificateModel) => {
+2 -3
View File
@@ -329,11 +329,10 @@ const WorkflowRunHistoryTable = ({ className, style }: { className?: string; sty
refreshData();
};
const { setData: setDetailRecord, setOpen: setDetailOpen, ...detailDrawerProps } = WorkflowRunDetailDrawer.useProps();
const { drawerProps: detailDrawerProps, ...detailDrawer } = WorkflowRunDetailDrawer.useDrawer();
const handleRecordDetailClick = (workflowRun: WorkflowRunModel) => {
setDetailRecord(workflowRun);
setDetailOpen(true);
detailDrawer.open(workflowRun);
};
return (
@@ -236,7 +236,7 @@ const WorkflowDetailRuns = () => {
});
if (cb.record.id === detailDrawerProps.data?.id) {
setDetailRecord({ ...detailDrawerProps.data, ...cb.record });
detailDrawerProps.data = { ...detailDrawerProps.data, ...cb.record };
}
if (cb.record.status !== WORKFLOW_RUN_STATUSES.PENDING && cb.record.status !== WORKFLOW_RUN_STATUSES.RUNNING) {
@@ -257,11 +257,10 @@ const WorkflowDetailRuns = () => {
setPageSize(pageSize);
};
const { setData: setDetailRecord, setOpen: setDetailOpen, ...detailDrawerProps } = WorkflowRunDetailDrawer.useProps();
const { drawerProps: detailDrawerProps, ...detailDrawer } = WorkflowRunDetailDrawer.useDrawer();
const handleRecordDetailClick = (workflowRun: WorkflowRunModel) => {
setDetailRecord(workflowRun);
setDetailOpen(true);
detailDrawer.open(workflowRun);
};
const handleRecordCancelClick = (workflowRun: WorkflowRunModel) => {