Skip to content

Commit

Permalink
feat: 添加ActionIconBox组件并在媒体元素中集成删除功能
Browse files Browse the repository at this point in the history
  • Loading branch information
chenshuai2144 committed Feb 18, 2025
1 parent 65f813b commit 7ba1fc1
Show file tree
Hide file tree
Showing 5 changed files with 243 additions and 32 deletions.
94 changes: 94 additions & 0 deletions src/MarkdownEditor/editor/components/ActionIconBox/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { LoadingOutlined } from '@ant-design/icons';
import { Button, ConfigProvider, Tooltip, TooltipProps } from 'antd';
import cx from 'classnames';
import React, { useContext, useEffect } from 'react';
import { useStyle } from './style';

/**
* Represents an icon item component.
* @param {React.ReactNode} children - The content of the icon item.
* @param {() => void} onClick - The callback function to be called when the icon item is clicked.
*/
export const ActionIconBox: React.FC<{
children: React.ReactNode;
showTitle?: boolean;
onClick?: (e: any) => void;
tooltipProps?: TooltipProps;
title: string;
type?: 'danger' | 'primary';
transform?: boolean;
className?: string;
borderLess?: boolean;
loading?: boolean;
style?: React.CSSProperties;
scale?: boolean;
active?: boolean;
standalone?: boolean;
onInit?: () => void;
noPadding?: boolean;
}> = (props) => {
const [loading, setLoading] = React.useState(false);
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('agent-chat-action-icon-box');
const { wrapSSR, hashId } = useStyle(prefixCls, props.style || {});
useEffect(() => {
props.onInit?.();
}, []);

if (props.standalone) {
return wrapSSR(
<Button
loading={loading}
icon={props.children as any}
onClick={async (e) => {
if (!props.onClick) return;
if (loading) return;
setLoading(true);
await props.onClick?.(e as any);
setLoading(false);
}}
type={props.type as 'primary'}
className={cx(prefixCls, hashId, props.className, {
[`${prefixCls}-standalone`]: props.standalone,
})}
style={props.style}
>
{props.title}
</Button>,
);
}
return wrapSSR(
<Tooltip title={props.title} {...props.tooltipProps}>
<span
className={cx(prefixCls, hashId, props.className, {
[`${prefixCls}-danger`]: props.type === 'danger',
[`${prefixCls}-primary`]: props.type === 'primary',
[`${prefixCls}-border-less`]: props.borderLess,
[`${prefixCls}-only-icon`]: props.scale,
[`${prefixCls}-active`]: props.active,
[`${prefixCls}-transform`]: props.transform,
[`${prefixCls}-noPadding`]: props.noPadding,
})}
onClick={async (e) => {
if (!props.onClick) return;
if (loading) return;
setLoading(true);
await props.onClick?.(e as any);
setLoading(false);
}}
style={props.style}
>
{loading || props.loading ? (
<LoadingOutlined />
) : (
React.cloneElement(props.children as any, {
onClick: props.onClick,
// @ts-ignore
...props?.children?.props,
})
)}
{props.showTitle && <span>{props.title}</span>}
</span>
</Tooltip>,
);
};
99 changes: 99 additions & 0 deletions src/MarkdownEditor/editor/components/ActionIconBox/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import {
ChatTokenType,
GenerateStyle,
resetComponent,
useEditorStyleRegister,
} from '../../utils/useStyle';

const genStyle: GenerateStyle<ChatTokenType> = (
token,
style: React.CSSProperties,
) => {
return {
[token.componentCls]: {
minWidth: 14,
minHeight: 14,
maxHeight: 24,
lineHeight: '1.5',
display: 'flex',
cursor: 'pointer',
padding: 4,
alignItems: 'center',
gap: 4,
transition: 'all 0.3s',
justifyContent: 'center',
borderRadius: token.borderRadius,
fontSize: '1em',
color: style.color || '#666F8D',
'&-noPadding': {
padding: 0,
},
'&:hover': {
color: token.colorPrimary,
background: token.colorBgTextHover,
},
'&-standalone': {
minWidth: 'inherit',
minHeight: 'inherit',
maxHeight: 'inherit',
padding: '8px 12px',
color: '#000000',
borderRadius: 18,
border: '1px solid #E6ECF4',
background: `radial-gradient(22% 66% at 96% 113%, rgba(255, 255, 245, 0.52) 0%, rgba(230, 238, 255, 0) 100%),radial-gradient(14% 234% at 100% 50%, rgba(162, 255, 255, 0.28) 0%, rgba(153, 202, 255, 0.1193) 13%, rgba(229, 189, 255, 0.0826) 38%, rgba(231, 211, 252, 0.0544) 59%, rgba(235, 255, 245, 0) 100%)`,
},
'&-danger': {
'&:hover': {
color: token.colorError,
background: token.colorErrorBgHover,
},
},
'&-primary': {
'&:hover': {
color: token.colorPrimary,
background: token.colorPrimaryBgHover,
},
},
'&-border-less': {
height: 'auto',
lineHeight: 1,
background: 'none!important',
'&:hover': {
color: token.colorPrimary,
background: 'none!important',
},
},
'&-only-icon': {
'&:hover': {
transform: 'scale(1.1)',
},
},
'&-transform': {
'&:hover': {
color: token.colorPrimary,
transform: 'translateX(8px) scale(1.1)',
background: 'none',
},
},
'&-active': {
color: token.colorPrimary,
},
},
};
};

/**
* ProchatItem
* @param prefixCls
* @returns
*/
export function useStyle(prefixCls: string, style: React.CSSProperties) {
return useEditorStyleRegister('ActionIconBox', (token) => {
const proChatToken = {
...token,
componentCls: `.${prefixCls}`,
};

return [genStyle(proChatToken, style), resetComponent(proChatToken)];
});
}
75 changes: 45 additions & 30 deletions src/MarkdownEditor/editor/elements/media.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { EyeOutlined } from '@ant-design/icons';
import { Image, ImageProps } from 'antd';
import { DeleteFilled, EyeOutlined } from '@ant-design/icons';
import { Image, ImageProps, Popover } from 'antd';
import React, { useCallback, useLayoutEffect, useMemo, useRef } from 'react';
import { ResizableBox } from 'react-resizable';

import classNames from 'classnames';
import { Transforms } from 'slate';
import { Path, Transforms } from 'slate';
import { ElementProps, MediaNode } from '../../el';
import { useSelStatus } from '../../hooks/editor';
import { ActionIconBox } from '../components/ActionIconBox';
import { AvatarList } from '../components/ContributorAvatar';
import { useEditorStore } from '../store';
import { DragHandle } from '../tools/DragHandle';
Expand Down Expand Up @@ -436,39 +437,53 @@ export function Media({
}}
>
<DragHandle />
<div
onClick={() => {
setTimeout(() => {
setState({ selected: true });
}, 16);
}}
onBlur={() => {
setState({ selected: false });
}}
tabIndex={-1}
style={{
color: 'transparent',
padding: 4,
userSelect: 'none',
display: 'flex',
flexDirection: 'column',
width: mediaElement ? '100%' : undefined,
}}
ref={htmlRef}
draggable={false}
contentEditable={false}
className="md-editor-media"
<Popover
trigger="click"
open={state().selected ? true : undefined}
content={
<ActionIconBox
title="删除"
onClick={() => {
Transforms.removeNodes(markdownEditorRef.current, {
at: Path.parent(path),
});
}}
>
<DeleteFilled />
</ActionIconBox>
}
>
{mediaElement}
{imageDom}
<div
onClick={() => {
setTimeout(() => {
setState({ selected: true });
}, 16);
}}
tabIndex={-1}
style={{
display: 'none',
color: 'transparent',
padding: 4,
userSelect: 'none',
display: 'flex',
flexDirection: 'column',
width: mediaElement ? '100%' : undefined,
}}
ref={htmlRef}
draggable={false}
contentEditable={false}
className="md-editor-media"
>
{children}
{mediaElement}
{imageDom}
<div
style={{
display: 'none',
}}
>
{children}
</div>
</div>
</div>
</Popover>
</div>
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion src/MarkdownEditor/editor/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ const genStyle: GenerateStyle<ChatTokenType> = (token) => {
paddingTop: '.25em',
paddingBottom: '.25em',
fontSize: '1em',
lineHeight: '1em',
lineHeight: '1.25em',
marginTop: '0',
marginBottom: '0.5em',
},
Expand Down
5 changes: 4 additions & 1 deletion src/MarkdownEditor/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@

.react-resizable {
position: relative;
transition: all 0.3s ease;
box-sizing: border-box;
border: 1px solid #eee;
}

.react-resizable-handle-hide {
Expand All @@ -41,7 +43,8 @@
transform: scale(1.02);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
border-radius: 4px;
transition: all 0.3s ease;
outline: 2px solid #1890ff;
outline-offset: 2px;
}
.react-resizable-handle {
position: absolute;
Expand Down

1 comment on commit 7ba1fc1

@vercel
Copy link

@vercel vercel bot commented on 7ba1fc1 Feb 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.