diff --git a/src/MessageModal/demos/index.tsx b/src/MessageModal/demos/index.tsx
new file mode 100644
index 00000000..e0c47cef
--- /dev/null
+++ b/src/MessageModal/demos/index.tsx
@@ -0,0 +1,19 @@
+import { MessageModal } from '@lobehub/ui';
+import { Button } from 'antd';
+import { useState } from 'react';
+
+export default () => {
+ const [open, setOpen] = useState(false);
+ return (
+ <>
+
+
+ >
+ );
+};
diff --git a/src/MessageModal/index.md b/src/MessageModal/index.md
new file mode 100644
index 00000000..81634bed
--- /dev/null
+++ b/src/MessageModal/index.md
@@ -0,0 +1,14 @@
+---
+nav: Components
+group: Chat
+title: MessageModal
+description: MessageModal
+---
+
+## Default
+
+
+
+## APIs
+
+
diff --git a/src/MessageModal/index.tsx b/src/MessageModal/index.tsx
new file mode 100644
index 00000000..2bfd08db
--- /dev/null
+++ b/src/MessageModal/index.tsx
@@ -0,0 +1,84 @@
+import { AimOutlined } from '@ant-design/icons';
+import { Modal } from 'antd';
+import { createStyles } from 'antd-style';
+import { memo } from 'react';
+import { Flexbox } from 'react-layout-kit';
+import useControlledState from 'use-merge-value';
+
+import Markdown from '@/Markdown';
+import MessageInput from '@/MessageInput';
+
+const useStyles = createStyles(({ css, prefixCls }) => ({
+ modal: css`
+ height: 70%;
+ .${prefixCls}-modal-header {
+ margin-bottom: 24px;
+ }
+ `,
+ body: css`
+ overflow-y: scroll;
+ max-height: 70vh;
+ `,
+}));
+
+export interface MessageModalProps {
+ open?: boolean;
+ onOpenChange?: (open: boolean) => void;
+ editing?: boolean;
+ onEditingChange?: (editing: boolean) => void;
+ onChange?: (text: string) => void;
+ value: string;
+}
+
+const MessageModal = memo(
+ ({ editing, open, onOpenChange, onEditingChange, value, onChange }) => {
+ const { styles } = useStyles();
+
+ const [isEdit, setTyping] = useControlledState(false, {
+ value: editing,
+ onChange: onEditingChange,
+ });
+
+ const [expand, setExpand] = useControlledState(false, {
+ value: open,
+ onChange: onOpenChange,
+ });
+
+ return (
+ setExpand(false)}
+ okText={'编辑'}
+ onOk={() => {
+ setTyping(true);
+ }}
+ footer={isEdit ? null : undefined}
+ cancelText={'关闭'}
+ title={
+
+
+ 提示词
+
+ }
+ className={styles.modal}
+ >
+ {isEdit ? (
+ {
+ setTyping(false);
+ onChange?.(text);
+ }}
+ onCancel={() => setTyping(false)}
+ defaultValue={value}
+ height={400}
+ />
+ ) : (
+ {value}
+ )}
+
+ );
+ },
+);
+
+export default MessageModal;
diff --git a/src/index.ts b/src/index.ts
index 5d30d1f1..225297c0 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -16,6 +16,7 @@ export { default as List } from './List';
export { default as Logo, type LogoProps } from './Logo';
export { default as Markdown, type MarkdownProps } from './Markdown';
export { default as MessageInput, type MessageInputProps } from './MessageInput';
+export { default as MessageModal, type MessageModalProps } from './MessageModal';
export { default as SearchBar, type SearchBarProps } from './SearchBar';
export { default as SideNav, type SideNavProps } from './SideNav';
export { default as Snippet, type SnippetProps } from './Snippet';