Refactor: Remove ant design component (#13143)

### What problem does this PR solve?

_Briefly describe what this PR aims to solve. Include background context
that will help reviewers understand the purpose of the PR._

### Type of change

- [x] Refactoring
This commit is contained in:
chanx
2026-02-13 18:40:41 +08:00
committed by GitHub
parent bc9ed24a85
commit f2a1d59c36
51 changed files with 1074 additions and 1484 deletions

View File

@@ -1,8 +1,9 @@
// src/components/ui/modal.tsx
import { cn } from '@/lib/utils';
import * as DialogPrimitive from '@radix-ui/react-dialog';
import { Loader, X } from 'lucide-react';
import { AlertCircle, CheckCircle, Info, Loader, X } from 'lucide-react';
import { FC, ReactNode, useCallback, useEffect, useMemo } from 'react';
import { createRoot } from 'react-dom/client';
import { useTranslation } from 'react-i18next';
import { DialogDescription } from '../dialog';
import { createPortalModal } from './modal-manage';
@@ -12,13 +13,15 @@ export interface ModalProps {
onOpenChange?: (open: boolean) => void;
title?: ReactNode;
titleClassName?: string;
children: ReactNode;
children?: ReactNode;
content?: ReactNode;
footer?: ReactNode;
footerClassName?: string;
showfooter?: boolean;
className?: string;
size?: 'small' | 'default' | 'large';
closable?: boolean;
showCancel?: boolean;
closeIcon?: ReactNode;
maskClosable?: boolean;
destroyOnClose?: boolean;
@@ -33,25 +36,42 @@ export interface ModalProps {
disabled?: boolean;
style?: React.CSSProperties;
zIndex?: number;
type?: 'warning' | 'info' | 'success' | 'error' | 'confirm';
}
export interface ModalType extends FC<ModalProps> {
show: typeof modalIns.show;
hide: typeof modalIns.hide;
destroy: typeof modalIns.destroy;
warning: (props: Omit<ModalProps, 'open' | 'type'>) => void;
info: (props: Omit<ModalProps, 'open' | 'type'>) => void;
success: (props: Omit<ModalProps, 'open' | 'type'>) => void;
error: (props: Omit<ModalProps, 'open' | 'type'>) => void;
confirm: (props: Omit<ModalProps, 'open' | 'type'>) => void;
}
const typeIcons = {
warning: <AlertCircle className="w-6 h-6 text-yellow-500" />,
info: <Info className="w-6 h-6 text-blue-500" />,
success: <CheckCircle className="w-6 h-6 text-green-500" />,
error: <AlertCircle className="w-6 h-6 text-red-500" />,
confirm: <AlertCircle className="w-6 h-6 text-yellow-500" />,
};
const Modal: ModalType = ({
open,
onOpenChange,
title,
titleClassName,
children,
content,
footer,
footerClassName,
showfooter = true,
className = '',
size = 'default',
closable = true,
showCancel = true,
closeIcon = <X className="w-4 h-4" />,
maskClosable = true,
destroyOnClose = false,
@@ -66,6 +86,7 @@ const Modal: ModalType = ({
disabled = false,
style,
zIndex = 50,
type,
}) => {
const sizeClasses = {
small: 'max-w-md',
@@ -74,7 +95,6 @@ const Modal: ModalType = ({
};
const { t } = useTranslation();
// Handle ESC key close
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape' && maskClosable) {
@@ -99,7 +119,6 @@ const Modal: ModalType = ({
return;
}
onOpenChange?.(open);
console.log('open', open, onOpenChange);
if (open && !disabled) {
onOk?.();
}
@@ -117,16 +136,18 @@ const Modal: ModalType = ({
} else {
footerTemp = (
<div className="flex justify-end gap-2">
<button
type="button"
onClick={() => handleCancel()}
className={cn(
'px-2 py-1 border border-border-button rounded-md hover:bg-bg-card hover:text-text-primary ',
cancelButtonClassName,
)}
>
{cancelText ?? t('modal.cancelText')}
</button>
{showCancel && (
<button
type="button"
onClick={() => handleCancel()}
className={cn(
'px-2 py-1 border border-border-button rounded-md hover:bg-bg-card hover:text-text-primary ',
cancelButtonClassName,
)}
>
{cancelText ?? t('modal.cancelText')}
</button>
)}
<button
type="button"
disabled={confirmLoading || disabled}
@@ -168,7 +189,28 @@ const Modal: ModalType = ({
footerClassName,
okButtonClassName,
cancelButtonClassName,
showCancel,
]);
const contentEl = useMemo(() => {
if (type && typeIcons[type]) {
return (
<div className="flex items-start gap-3">
<div className="flex-shrink-0 mt-0.5">{typeIcons[type]}</div>
<div className="flex-1">
{title && (
<DialogPrimitive.Title className="text-lg font-medium text-foreground mb-2">
{title}
</DialogPrimitive.Title>
)}
<div className="text-text-secondary">{content || children}</div>
</div>
</div>
);
}
return children;
}, [type, title, content, children]);
return (
<DialogPrimitive.Root open={open} onOpenChange={handleChange}>
<DialogPrimitive.Portal>
@@ -180,22 +222,16 @@ const Modal: ModalType = ({
<DialogPrimitive.Content
className={cn(
`relative w-[700px] ${full ? 'max-w-full' : sizeClasses[size]} ${className} bg-bg-base rounded-lg shadow-lg border border-border-default transition-all focus-visible:!outline-none`,
{ 'pt-10': closable && !title },
{ 'pt-10': closable && !title && !type },
)}
style={style}
onClick={(e) => e.stopPropagation()}
>
<DialogDescription></DialogDescription>
{/* title */}
{title && (
{title && !type && (
<div
className={cn(
'flex items-start px-6 py-4 justify-start',
// {
// 'justify-end': closable && !title,
// 'justify-between': closable && title,
// 'justify-start': !closable,
// },
titleClassName,
)}
>
@@ -218,12 +254,10 @@ const Modal: ModalType = ({
</DialogPrimitive.Close>
)}
{/* content */}
<div className="py-2 px-6 overflow-y-auto scrollbar-auto max-h-[calc(100vh-280px)] focus-visible:!outline-none">
{destroyOnClose && !open ? null : children}
{destroyOnClose && !open ? null : contentEl}
</div>
{/* footer */}
{footEl}
</DialogPrimitive.Content>
</DialogPrimitive.Overlay>
@@ -242,4 +276,49 @@ Modal.show = modalIns
Modal.hide = modalIns.hide;
Modal.destroy = modalIns.destroy;
const createStaticModal = (type: ModalProps['type']) => {
return (props: Omit<ModalProps, 'open' | 'type'>) => {
const container = document.createElement('div');
document.body.appendChild(container);
const root = createRoot(container);
const destroy = () => {
root.unmount();
container.remove();
};
const handleOk = () => {
props.onOk?.();
destroy();
};
const handleCancel = () => {
props.onCancel?.();
destroy();
};
root.render(
<Modal
{...props}
open={true}
type={type}
onOk={handleOk}
onCancel={handleCancel}
onOpenChange={(open) => {
if (!open) {
handleCancel();
}
}}
maskClosable={false}
/>,
);
};
};
Modal.warning = createStaticModal('warning');
Modal.info = createStaticModal('info');
Modal.success = createStaticModal('success');
Modal.error = createStaticModal('error');
Modal.confirm = createStaticModal('confirm');
export { Modal };