Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 支持配置自定义的 Tag 配置来完成额外的换起和插入 #54

Merged
merged 8 commits into from
Mar 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/MarkdownEditor/demos/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,18 @@ export default () => {
width={'100vw'}
height={'100vh'}
reportMode
tag={{
items: [
{
label: '腾讯',
key: 'tencent',
},
{
label: '阿里巴巴',
key: 'alibaba',
},
],
}}
plugins={[
{
elements: {
Expand Down
36 changes: 32 additions & 4 deletions src/MarkdownEditor/editor/Editor.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* eslint-disable react/no-children-prop */
import { message } from 'antd';
import { MenuProps, message } from 'antd';
import classNames from 'classnames';
import { observer } from 'mobx-react';
import React, { useContext, useEffect, useMemo, useRef } from 'react';
import React, { ReactNode, useContext, useEffect, useMemo, useRef } from 'react';
import {
BaseRange,
BaseSelection,
Expand Down Expand Up @@ -47,6 +47,8 @@ import {
isPath,
} from './utils/editorUtils';
import { toUnixPath } from './utils/path';
import { TagPopupProps } from './elements/code/TagPopup';


export type MEditorProps = {
eleItemRender?: MarkdownEditorProps['eleItemRender'];
Expand All @@ -56,6 +58,7 @@ export type MEditorProps = {
comment?: MarkdownEditorProps['comment'];
prefixCls?: string;
reportMode?: MarkdownEditorProps['reportMode'];
tag?: TagPopupProps;
titlePlaceholderContent?: string;
} & MarkdownEditorProps;

Expand All @@ -76,12 +79,21 @@ const genTableMinSize = (
};

export const MEditor = observer(
({ eleItemRender, reportMode, instance, ...editorProps }: MEditorProps) => {
({
eleItemRender,
reportMode,
tag,
instance,
...editorProps
}: MEditorProps) => {
const { store, markdownEditorRef, markdownContainerRef, readonly } =
useEditorStore();
const changedMark = useRef(false);
const value = useRef<any[]>([EditorUtils.p]);
const nodeRef = useRef<MarkdownEditorInstance>();
const {
prefixCls = '$',
} = tag || {};

const onKeyDown = useKeyboard(
store,
Expand All @@ -96,6 +108,21 @@ export const MEditor = observer(
const high = useHighlight(store);
const first = useRef(true);

const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
if (event?.key === prefixCls) {
Transforms.insertNodes(
markdownEditorRef.current,{
type: "code",
code: true,
tag: {
...tag
},
text: ''
})
}
onKeyDown(event);
};

/**
* 初始化编辑器
*/
Expand Down Expand Up @@ -706,6 +733,7 @@ export const MEditor = observer(
event.preventDefault();
}}
onMouseDown={checkEnd}

onFocus={onFocus}
onBlur={onBlur}
onPaste={onPaste}
Expand Down Expand Up @@ -735,7 +763,7 @@ export const MEditor = observer(
onCompositionStart={onCompositionStart}
onCompositionEnd={onCompositionEnd}
renderElement={elementRenderElement}
onKeyDown={onKeyDown}
onKeyDown={handleKeyDown}
renderLeaf={renderMarkdownLeaf}
/>
</Slate>
Expand Down
101 changes: 101 additions & 0 deletions src/MarkdownEditor/editor/elements/code/TagPopup/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { Dropdown, MenuProps } from 'antd';
import React, { ReactNode } from 'react';

type TagPopupProps = {
children?: React.ReactNode;
onSelect?: (value: string) => void;
items?: Array<{
label: string;
key: string | number;
onClick?: (v: string) => void;
}>;
prefixCls?: string;
dropdownRender?: (defaultdom: ReactNode) => React.ReactNode;
dropdownStyle?: React.CSSProperties;
menu?: MenuProps;
notFoundContent?: React.ReactNode;
bodyStyle?: React.CSSProperties;
className?: string;
};

const TagPopup = (
props: TagPopupProps & {
text: {
text: string;
};
},
) => {
console.log('Tag Props', props);
const {
items = [],
onSelect,
children,
dropdownRender,
dropdownStyle,
menu,
prefixCls,
notFoundContent,
className,
text,
} = props || {};
console.log('children', children);

const { text: inputValue } = text;
console.log('inputValuetext', text);

const [open, setOpen] = React.useState(true);

const MergedItem = items.map((item) => {
const { key } = item || {};
return {
...item,
onClick: () => {
onSelect && onSelect(`${key}` || '');
setOpen(false);
},
};
});

return (
<Dropdown
open={open}
className={className}
dropdownRender={(defalutDom) => {
if (dropdownRender) {
return dropdownRender(defalutDom);
} else if (menu! && items!) {
return notFoundContent || '';
} else {
return defalutDom;
}
}}
overlayStyle={dropdownStyle}
menu={
menu
? menu
: {
items: MergedItem,
}
}
>
<div
onClick={() => {
setOpen(true);
}}
style={{
backgroundColor: '#f5f5f5',
padding: '0 4px',
borderRadius: 4,
fontSize: '1em',
display: 'inline-block',
lineHeight: '24px',
color: '#bfbfbf',
}}
>
{children}
</div>
</Dropdown>
);
};

export { TagPopup, TagPopupProps };
57 changes: 41 additions & 16 deletions src/MarkdownEditor/editor/elements/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import React, { CSSProperties, useContext } from 'react';
import { Editor, Transforms } from 'slate';

import { ExportOutlined } from '@ant-design/icons';
import { MarkdownEditorProps } from '../../BaseMarkdownEditor';
import {
ReactEditor,
RenderElementProps,
Expand All @@ -15,6 +14,7 @@ import { EditorUtils } from '../utils/editorUtils';
import { InlineChromiumBugfix } from '../utils/InlineChromiumBugfix';
import { Blockquote } from './blockquote';
import { WarpCard } from './card';
import { TagPopup } from './code/TagPopup';
import { ColumnCell, ColumnGroup } from './column';
import { CommentView } from './Comment';
import { Description } from './description';
Expand All @@ -27,6 +27,8 @@ import { Media } from './media';
import { Paragraph } from './paragraph';
import { Schema } from './schema';
import { Table, TableCell } from './Table/index';
import { InlineKatex } from '@ant-design/md-editor/plugins/code';
import { MarkdownEditorProps } from '../../BaseMarkdownEditor';

const dragStart = (e: React.DragEvent) => {
e.preventDefault();
Expand Down Expand Up @@ -68,7 +70,7 @@ export const MElement = (
case 'break':
return (
<span {...props.attributes} contentEditable={false}>
<span style={{ display: 'none' }}>{props.children}</span>
{props.children}
<br />
</span>
);
Expand Down Expand Up @@ -133,6 +135,9 @@ export const MElement = (
{props.children}
</span>
);

case 'inline-katex':
return <InlineKatex {...props} />;
default:
return <Paragraph {...props} />;
}
Expand All @@ -148,19 +153,39 @@ export const MLeaf = (
const { markdownEditorRef, readonly } = useEditorStore();
const context = useContext(ConfigProvider.ConfigContext);
const mdEditorBaseClass = context.getPrefixCls('md-editor-content');

const leaf = props.leaf;
const style: CSSProperties = {};
let className = props.hashId + ' ';
let children = <>{props.children}</>;
if (leaf.code)
children = (
<code
className={classNames(mdEditorBaseClass + '-inline-code', props.hashId)}
>
{children}
</code>
);
if (leaf.code) {
const { tag, text } = props?.leaf || {};
const { prefixCls = '$' } = tag || {};
if (tag && leaf.text?.startsWith(prefixCls)) {
children = (
<TagPopup
{...props?.leaf?.tag}
text={text}
onSelect={(v) => {
markdownEditorRef.current.insertText(v);
}}
>
{children}
</TagPopup>
);
} else {
children = (
<code
className={classNames(
mdEditorBaseClass + '-inline-code',
props.hashId,
)}
>
{children}
</code>
);
}
}

if (leaf.highColor) style.color = leaf.highColor;
if (leaf.color) style.color = leaf.color;
if (leaf.bold) style.fontWeight = 'bold';
Expand Down Expand Up @@ -263,6 +288,7 @@ export const MLeaf = (
selectFormat();
}
}}
contentEditable={leaf.fnc ? false : undefined}
data-fnc={leaf.fnc || leaf.identifier ? 'fnc' : undefined}
data-fnd={leaf.fnd ? 'fnd' : undefined}
data-comment={leaf.comment ? 'comment' : undefined}
Expand All @@ -284,15 +310,14 @@ export const MLeaf = (
>
{!!dirty && !!leaf.text && <InlineChromiumBugfix />}
{leaf.fnc || leaf.identifier
? leaf.text
?.replaceAll(']', '')
?.replaceAll('[^DOC_', '')
?.replaceAll('[^', '')
? leaf.text
?.replaceAll(']', '')
?.replaceAll('[^DOC_', '')
?.replaceAll('[^', '')
: children}
{!!dirty && !!leaf.text && <InlineChromiumBugfix />}
</span>
);

if (props.fncProps?.render && (leaf.fnc || leaf.identifier)) {
dom = (
<>
Expand Down
4 changes: 4 additions & 0 deletions src/MarkdownEditor/editor/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,10 @@ const genSlideStyle: GenerateStyle<ChatTokenType> = (token) => {
},
},
},
[`${token.componentCls}-tag`]: {
position: 'absolute',
zIndex: 1000,
},
};
};

Expand Down
Loading